Recolha registos JSON de colaboração do Box
Este documento explica como carregar registos JSON de colaboração do Box para o Google Security Operations através do AWS S3 com o agendamento do Lambda e do EventBridge. O analisador processa registos de eventos do Box no formato JSON, mapeando-os para um modelo de dados unificado (UDM). Extrai campos relevantes dos registos não processados, executa transformações de dados, como a mudança de nome e a união, e enriquece os dados com informações intermédias antes de gerar os dados de eventos estruturados.
Antes de começar
- Instância do Google SecOps
- Acesso privilegiado ao Box (consola do administrador + programador)
- Acesso privilegiado à AWS (S3, IAM, Lambda, EventBridge) na mesma região onde planeia armazenar os registos
Configure a Box Developer Console (credenciais de cliente)
- Inicie sessão na Box Developer Console.
- Crie uma app personalizada com autenticação do servidor (concessão de credenciais do cliente).
- Defina Acesso à aplicação = App + acesso empresarial.
- Em Âmbitos da aplicação, ative a opção Gerir propriedades empresariais.
- Na consola do administrador > Apps > Gestor de apps personalizadas, autorize a app através do ID do cliente.
- Copie e guarde o ID de cliente e o * segredo do cliente num local seguro.
- Aceda à consola do administrador > Conta e faturação > Informações da conta.
- Copie e guarde o ID empresarial num local seguro.
Configure o contentor do AWS S3 e o IAM para o Google SecOps
- Crie um contentor do Amazon S3 seguindo este manual do utilizador: Criar um contentor
- Guarde o nome e a região do contentor para referência futura (por exemplo,
box-collaboration-logs
). - Crie um utilizador seguindo este guia do utilizador: Criar um utilizador do IAM.
- Selecione o utilizador criado.
- Selecione o separador Credenciais de segurança.
- Clique em Criar chave de acesso na secção Chaves de acesso.
- Selecione Serviço de terceiros como o Exemplo de utilização.
- Clicar em Seguinte.
- Opcional: adicione uma etiqueta de descrição.
- Clique em Criar chave de acesso.
- Clique em Transferir ficheiro CSV para guardar a chave de acesso e a chave de acesso secreta para utilização posterior.
- Clique em Concluído.
- Selecione o separador Autorizações.
- Clique em Adicionar autorizações na secção Políticas de autorizações.
- Selecione Adicionar autorizações.
- Selecione Anexar políticas diretamente
- Pesquise e selecione a política AmazonS3FullAccess.
- Clicar em Seguinte.
- Clique em Adicionar autorizações.
Configure a política e a função de IAM para carregamentos do S3
- Na consola da AWS, aceda a IAM > Políticas > Criar política > separador JSON.
Introduza a seguinte 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" } ] }
- Substitua
box-collaboration-logs
se tiver introduzido um nome de contentor diferente.
- Substitua
Clique em Seguinte > Criar política.
Aceda a IAM > Funções > Criar função > Serviço AWS > Lambda.
Anexe a política criada recentemente.
Dê o nome
WriteBoxToS3Role
à função e clique em Criar função.
Crie a função Lambda
- Na consola da AWS, aceda a Lambda > Functions > Create function.
- Clique em Criar do zero.
Faculte os seguintes detalhes de configuração:
Definição Valor Nome box_collaboration_to_s3
Runtime Python 3.13 Arquitetura x86_64 Função de execução WriteBoxToS3Role
Depois de criar a função, abra o separador Código, elimine o fragmento e introduza o seguinte 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}
Aceda a Configuração > Variáveis de ambiente > Editar > Adicionar nova variável de ambiente.
Introduza as seguintes variáveis de ambiente, substituindo-as pelos seus valores:
Chave Exemplo S3_BUCKET
box-collaboration-logs
S3_PREFIX
box/collaboration/
STATE_KEY
box/collaboration/state.json
BOX_CLIENT_ID
Introduza o ID de cliente do Box BOX_CLIENT_SECRET
Introduza o segredo do cliente do Box BOX_ENTERPRISE_ID
Introduza o ID do Box Enterprise STREAM_TYPE
admin_logs_streaming
LIMIT
500
Depois de criar a função, permaneça na respetiva página (ou abra Lambda > Functions > your-function).
Selecione o separador Configuração.
No painel Configuração geral, clique em Editar.
Altere Tempo limite para 10 minutos (600 segundos) e clique em Guardar.
Agende a função Lambda (EventBridge Scheduler)
- Aceda a Amazon EventBridge > Scheduler > Create schedule.
- Indique os seguintes detalhes de configuração:
- Agenda recorrente: Taxa (
15 min
). - Alvo: a sua função Lambda.
- Nome:
box-collaboration-schedule-15min
.
- Agenda recorrente: Taxa (
- Clique em Criar programação.
Configure um feed no Google SecOps para carregar registos do Box
- Aceda a Definições do SIEM > Feeds.
- Clique em Adicionar novo feed.
- No campo Nome do feed, introduza um nome para o feed (por exemplo,
Box Collaboration
). - Selecione Amazon S3 V2 como o Tipo de origem.
- Selecione Caixa como o Tipo de registo.
- Clicar em Seguinte.
- Especifique valores para os seguintes parâmetros de entrada:
- URI do S3: o URI do contentor (o formato deve ser:
s3://box-collaboration-logs/box/collaboration/
). Substituabox-collaboration-logs
: use o nome real do contentor. - Opções de eliminação de origens: selecione a opção de eliminação de acordo com a sua preferência.
- Idade máxima do ficheiro: inclua ficheiros modificados no último número de dias. A predefinição é 180 dias.
- ID da chave de acesso: chave de acesso do utilizador com acesso ao contentor do S3.
- Chave de acesso secreta: chave secreta do utilizador com acesso ao contentor do S3.
- Espaço de nomes do recurso: o espaço de nomes do recurso.
- Etiquetas de carregamento: a etiqueta a aplicar aos eventos deste feed.
- URI do S3: o URI do contentor (o formato deve ser:
- Clicar em Seguinte.
- Reveja a nova configuração do feed no ecrã Finalizar e, de seguida, clique em Enviar.
Tabela de mapeamento da UDM
Campo de registo | Mapeamento do UDM | Lógica |
---|---|---|
additional_details.ekm_id | additional.fields | Valor retirado de additional_details.ekm_id |
additional_details.service_id | additional.fields | Valor obtido de additional_details.service_id |
additional_details.service_name | additional.fields | Valor retirado de additional_details.service_name |
additional_details.shared_link_id | additional.fields | Valor retirado de additional_details.shared_link_id |
additional_details.size | target.file.size | Valor retirado de additional_details.size |
additional_details.version_id | additional.fields | Valor retirado de additional_details.version_id |
created_at | metadata.event_timestamp | Valor retirado de created_at |
created_by.id | principal.user.userid | Valor retirado de created_by.id |
created_by.login | principal.user.email_addresses | Valor retirado de created_by.login |
created_by.name | principal.user.user_display_name | Valor retirado de created_by.name |
event_id | metadata.product_log_id | Valor retirado de event_id |
event_type | metadata.product_event_type | Valor retirado de event_type |
ip_address | principal.ip | Valor retirado de ip_address |
source.item_id | target.file.product_object_id | Valor retirado de source.item_id |
source.item_name | target.file.full_path | Valor retirado de source.item_name |
source.item_type | Não mapeado | |
source.login | target.user.email_addresses | Valor retirado de source.login |
source.name | target.user.user_display_name | Valor retirado de source.name |
source.owned_by.id | target.user.userid | Valor retirado de source.owned_by.id |
source.owned_by.login | target.user.email_addresses | Valor retirado de source.owned_by.login |
source.owned_by.name | target.user.user_display_name | Valor retirado de source.owned_by.name |
source.parent.id | Não mapeado | |
source.parent.name | Não mapeado | |
source.parent.type | Não mapeado | |
source.type | Não mapeado | |
escrever | metadata.log_type | Valor retirado do tipo |
metadata.vendor_name | Valor codificado | |
metadata.product_name | Valor codificado | |
security_result.action | Derivado de event_type. Se event_type for FAILED_LOGIN, então BLOCK. Se event_type for USER_LOGIN, então ALLOW. Caso contrário, UNSPECIFIED. | |
extensions.auth.type | Derivado de event_type. Se event_type for USER_LOGIN ou ADMIN_LOGIN, então MACHINE; caso contrário, UNSPECIFIED. | |
extensions.auth.mechanism | Derivado de event_type. Se event_type for USER_LOGIN ou ADMIN_LOGIN, então USERNAME_PASSWORD. Caso contrário, UNSPECIFIED. |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais da Google SecOps.