Recopila registros JSON de colaboración de Box
En este documento, se explica cómo transferir registros JSON de colaboración de Box a Google Security Operations con AWS S3 a través de la programación de Lambda y EventBridge. El analizador procesa los registros de eventos de Box en formato JSON y los asigna a un modelo de datos unificado (UDM). Extrae los campos pertinentes de los registros sin procesar, realiza transformaciones de datos, como cambiar el nombre y combinar, y enriquece los datos con información intermedia antes de generar los datos de eventos estructurados.
Antes de comenzar
- Instancia de Google SecOps
- Acceso con privilegios a Box (Consola del administrador y Consola para desarrolladores)
- Acceso privilegiado a AWS (S3, IAM, Lambda, EventBridge) en la misma región en la que planeas almacenar los registros
Configura Box Developer Console (credenciales de cliente)
- Accede a Box Developer Console.
- Crea una app personalizada con autenticación de servidor (otorgamiento de credenciales de cliente).
- Establece Application Access en App + Enterprise Access.
- En Application Scopes, habilita Manage enterprise properties.
- En Consola del administrador > Apps > Administrador de apps personalizadas, autoriza la app con el ID de cliente.
- Copia y guarda el ID de cliente y el * secreto del cliente en una ubicación segura.
- Ve a Consola del administrador > Cuenta y facturación > Información de la cuenta.
- Copia y guarda el ID de la empresa en una ubicación segura.
Configura el bucket de AWS S3 y el IAM para Google SecOps
- Crea un bucket de Amazon S3 siguiendo esta guía del usuario: Crea un bucket
- Guarda el Nombre y la Región del bucket para futuras referencias (por ejemplo,
box-collaboration-logs
). - Crea un usuario siguiendo esta guía del usuario: Cómo crear un usuario de IAM.
- Selecciona el usuario creado.
- Selecciona la pestaña Credenciales de seguridad.
- Haz clic en Crear clave de acceso en la sección Claves de acceso.
- Selecciona Servicio de terceros como el Caso de uso.
- Haz clic en Siguiente.
- Opcional: Agrega una etiqueta de descripción.
- Haz clic en Crear clave de acceso.
- Haz clic en Descargar archivo CSV para guardar la clave de acceso y la clave de acceso secreta para usarlas más adelante.
- Haz clic en Listo.
- Selecciona la pestaña Permisos.
- Haz clic en Agregar permisos en la sección Políticas de permisos.
- Selecciona Agregar permisos.
- Selecciona Adjuntar políticas directamente.
- Busca y selecciona la política AmazonS3FullAccess.
- Haz clic en Siguiente.
- Haz clic en Agregar permisos.
Configura la política y el rol de IAM para las cargas de S3
- En la consola de AWS, ve a IAM > Políticas > Crear política > pestaña JSON.
Ingresa la siguiente política:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPutBoxObjects", "Effect": "Allow", "Action": ["s3:PutObject"], "Resource": "arn:aws:s3:::box-collaboration-logs/*" }, { "Sid": "AllowGetStateObject", "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::box-collaboration-logs/box/collaboration/state.json" } ] }
- Reemplaza
box-collaboration-logs
si ingresaste un nombre de bucket diferente.
- Reemplaza
Haz clic en Siguiente > Crear política.
Ve a IAM > Roles > Crear rol > Servicio de AWS > Lambda.
Adjunta la política recién creada.
Asigna el nombre
WriteBoxToS3Role
al rol y haz clic en Crear rol.
Crea la función Lambda
- En la consola de AWS, ve a Lambda > Functions > Create function.
- Haz clic en Crear desde cero.
Proporciona los siguientes detalles de configuración:
Configuración Valor Nombre box_collaboration_to_s3
Tiempo de ejecución Python 3.13 Arquitectura x86_64 Rol de ejecución WriteBoxToS3Role
Después de crear la función, abre la pestaña Code, borra el código auxiliar y, luego, ingresa el siguiente código (
box_collaboration_to_s3.py
):#!/usr/bin/env python3 # Lambda: Pull Box Enterprise Events to S3 (no transform) import os, json, time, urllib.parse from urllib.request import Request, urlopen from urllib.error import HTTPError, URLError import boto3 TOKEN_URL = "https://api.box.com/oauth2/token" EVENTS_URL = "https://api.box.com/2.0/events" CID = os.environ["BOX_CLIENT_ID"] CSECRET = os.environ["BOX_CLIENT_SECRET"] ENT_ID = os.environ["BOX_ENTERPRISE_ID"] STREAM_TYPE = os.environ.get("STREAM_TYPE", "admin_logs_streaming") LIMIT = int(os.environ.get("LIMIT", "500")) BUCKET = os.environ["S3_BUCKET"] PREFIX = os.environ.get("S3_PREFIX", "box/collaboration/") STATE_KEY = os.environ.get("STATE_KEY", "box/collaboration/state.json") s3 = boto3.client("s3") def get_state(): try: obj = s3.get_object(Bucket=BUCKET, Key=STATE_KEY) data = json.loads(obj["Body"].read()) return data.get("stream_position") except Exception: return None def put_state(pos): body = json.dumps({"stream_position": pos}, separators=(",", ":")).encode("utf-8") s3.put_object(Bucket=BUCKET, Key=STATE_KEY, Body=body, ContentType="application/json") def get_token(): body = urllib.parse.urlencode({ "grant_type": "client_credentials", "client_id": CID, "client_secret": CSECRET, "box_subject_type": "enterprise", "box_subject_id": ENT_ID, }).encode() req = Request(TOKEN_URL, data=body, method="POST") req.add_header("Content-Type", "application/x-www-form-urlencoded") with urlopen(req, timeout=30) as r: tok = json.loads(r.read().decode()) return tok["access_token"] def fetch_events(token, stream_position=None, timeout=60, max_retries=5): params = {"stream_type": STREAM_TYPE, "limit": LIMIT, "stream_position": stream_position or "now"} qs = urllib.parse.urlencode(params) attempt, backoff = 0, 1.0 while True: try: req = Request(f"{EVENTS_URL}?{qs}", method="GET") req.add_header("Authorization", f"Bearer {token}") with urlopen(req, timeout=timeout) as r: return json.loads(r.read().decode()) except HTTPError as e: if e.code == 429 and attempt < max_retries: ra = e.headers.get("Retry-After") delay = int(ra) if (ra and ra.isdigit()) else int(backoff) time.sleep(max(1, delay)); attempt += 1; backoff *= 2; continue if 500 <= e.code <= 599 and attempt < max_retries: time.sleep(backoff); attempt += 1; backoff *= 2; continue raise except URLError: if attempt < max_retries: time.sleep(backoff); attempt += 1; backoff *= 2; continue raise def write_chunk(data): ts = time.strftime("%Y/%m/%d/%H%M%S", time.gmtime()) key = f"{PREFIX}/{ts}-box-events.json" s3.put_object(Bucket=BUCKET, Key=key, Body=json.dumps(data, separators=(",", ":")).encode("utf-8"), ContentType="application/json") return key def lambda_handler(event=None, context=None): token = get_token() pos = get_state() total, idx = 0, 0 while True: page = fetch_events(token, pos) entries = page.get("entries") or [] if not entries: next_pos = page.get("next_stream_position") or pos if next_pos and next_pos != pos: put_state(next_pos) break # уникальный ключ ts = time.strftime("%Y/%m/%d/%H%M%S", time.gmtime()) key = f"{PREFIX}/{ts}-box-events-{idx:03d}.json" s3.put_object(Bucket=BUCKET, Key=key, Body=json.dumps(page, separators=(",", ":")).encode("utf-8"), ContentType="application/json") idx += 1 total += len(entries) pos = page.get("next_stream_position") or pos if pos: put_state(pos) if len(entries) < LIMIT: break return {"ok": True, "written": total, "next_stream_position": pos}
Ve a Configuración > Variables de entorno > Editar > Agregar nueva variable de entorno.
Ingresa las siguientes variables de entorno y reemplaza los valores por los tuyos:
Clave Ejemplo S3_BUCKET
box-collaboration-logs
S3_PREFIX
box/collaboration/
STATE_KEY
box/collaboration/state.json
BOX_CLIENT_ID
Ingresa el ID de cliente de Box BOX_CLIENT_SECRET
Ingresa el secreto del cliente de Box BOX_ENTERPRISE_ID
Ingresa el ID de la empresa de Box STREAM_TYPE
admin_logs_streaming
LIMIT
500
Después de crear la función, permanece en su página (o abre Lambda > Functions > tu-función).
Selecciona la pestaña Configuración.
En el panel Configuración general, haz clic en Editar.
Cambia Tiempo de espera a 10 minutos (600 segundos) y haz clic en Guardar.
Programa la función de Lambda (EventBridge Scheduler)
- Ve a Amazon EventBridge > Scheduler > Create schedule.
- Proporciona los siguientes detalles de configuración:
- Programación recurrente: Frecuencia (
15 min
). - Destino: Tu función Lambda.
- Nombre:
box-collaboration-schedule-15min
.
- Programación recurrente: Frecuencia (
- Haz clic en Crear programación.
Configura un feed en Google SecOps para transferir registros de Box
- Ve a SIEM Settings > Feeds.
- Haz clic en Agregar feed nuevo.
- En el campo Nombre del feed, ingresa un nombre para el feed (por ejemplo,
Box Collaboration
). - Selecciona Amazon S3 V2 como el Tipo de fuente.
- Selecciona Box como el Tipo de registro.
- Haz clic en Siguiente.
- Especifica valores para los siguientes parámetros de entrada:
- URI de S3: Es el URI del bucket (el formato debe ser
s3://box-collaboration-logs/box/collaboration/
). Reemplazabox-collaboration-logs
por el nombre real del bucket. - Opciones de borrado de la fuente: Selecciona la opción de borrado según tu preferencia.
- Antigüedad máxima del archivo: Incluye los archivos modificados en la cantidad de días especificada. El valor predeterminado es 180 días.
- ID de clave de acceso: Clave de acceso del usuario con acceso al bucket de S3.
- Clave de acceso secreta: Clave secreta del usuario con acceso al bucket de S3.
- Espacio de nombres del recurso: Es el espacio de nombres del recurso.
- Etiquetas de transmisión: Es la etiqueta que se aplicará a los eventos de este feed.
- URI de S3: Es el URI del bucket (el formato debe ser
- Haz clic en Siguiente.
- Revisa la nueva configuración del feed en la pantalla Finalizar y, luego, haz clic en Enviar.
Tabla de asignación de UDM
Campo de registro | Asignación de UDM | Lógica |
---|---|---|
additional_details.ekm_id | additional.fields | Valor tomado de additional_details.ekm_id |
additional_details.service_id | additional.fields | Valor tomado de additional_details.service_id |
additional_details.service_name | additional.fields | Valor tomado de additional_details.service_name |
additional_details.shared_link_id | additional.fields | Valor tomado de additional_details.shared_link_id |
additional_details.size | target.file.size | Valor tomado de additional_details.size |
additional_details.version_id | additional.fields | Valor tomado de additional_details.version_id |
created_at | metadata.event_timestamp | Valor tomado de created_at |
created_by.id | principal.user.userid | Valor tomado de created_by.id |
created_by.login | principal.user.email_addresses | Valor tomado de created_by.login |
created_by.name | principal.user.user_display_name | Valor tomado de created_by.name |
event_id | metadata.product_log_id | Valor tomado de event_id |
event_type | metadata.product_event_type | Valor tomado de event_type |
ip_address | principal.ip | Valor tomado de ip_address |
source.item_id | target.file.product_object_id | Valor tomado de source.item_id |
source.item_name | target.file.full_path | Valor tomado de source.item_name |
source.item_type | Sin asignación | |
source.login | target.user.email_addresses | Valor tomado de source.login |
source.name | target.user.user_display_name | Valor tomado de source.name |
source.owned_by.id | target.user.userid | Valor tomado de source.owned_by.id |
source.owned_by.login | target.user.email_addresses | Valor tomado de source.owned_by.login |
source.owned_by.name | target.user.user_display_name | Valor tomado de source.owned_by.name |
source.parent.id | Sin asignación | |
source.parent.name | Sin asignación | |
source.parent.type | Sin asignación | |
source.type | Sin asignación | |
tipo | metadata.log_type | Valor tomado del tipo |
metadata.vendor_name | Valor codificado | |
metadata.product_name | Valor codificado | |
security_result.action | Se deriva de event_type. Si event_type es FAILED_LOGIN, se establece en BLOCK; si event_type es USER_LOGIN, se establece en ALLOW; de lo contrario, se establece en UNSPECIFIED. | |
extensions.auth.type | Se deriva de event_type. Si event_type es USER_LOGIN o ADMIN_LOGIN, entonces MACHINE; de lo contrario, UNSPECIFIED. | |
extensions.auth.mechanism | Se deriva de event_type. Si event_type es USER_LOGIN o ADMIN_LOGIN, entonces USERNAME_PASSWORD; de lo contrario, UNSPECIFIED. |
¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.