Raccogliere i log JSON di Box Collaboration

Supportato in:

Questo documento spiega come importare i log JSON di Box Collaboration in Google Security Operations utilizzando AWS S3 tramite la pianificazione di Lambda ed EventBridge. Il parser elabora i log degli eventi di Box in formato JSON, mappandoli a un modello UDM (Unified Data Model). Estrae i campi pertinenti dai log non elaborati, esegue trasformazioni dei dati come la ridenominazione e l'unione e arricchisce i dati con informazioni intermedie prima di restituire i dati sugli eventi strutturati.

Prima di iniziare

  • Istanza Google SecOps
  • Accesso privilegiato a Box (console di amministrazione + console per gli sviluppatori)
  • Accesso privilegiato ad AWS (S3, IAM, Lambda, EventBridge) nella stessa regione in cui prevedi di archiviare i log

Configura la console per sviluppatori Box (credenziali client)

  1. Accedi alla console per sviluppatori di Box.
  2. Crea un'app personalizzata con autenticazione server (concessione delle credenziali client).
  3. Imposta Application Access (Accesso alle applicazioni) = App + Enterprise Access (App + Accesso aziendale).
  4. In Ambiti delle applicazioni, attiva Gestisci proprietà aziendali.
  5. Nella Console di amministrazione > App > Gestore app personalizzate, autorizza l'app tramite l'ID client.
  6. Copia e salva l'ID client e il * client secret in una posizione sicura.
  7. Vai alla Console di amministrazione > Account e fatturazione > Informazioni sull'account.
  8. Copia e salva l'ID enterprise in un luogo sicuro.

Configura il bucket AWS S3 e IAM per Google SecOps

  1. Crea un bucket Amazon S3 seguendo questa guida utente: Creazione di un bucket
  2. Salva il nome e la regione del bucket per riferimento futuro (ad esempio, box-collaboration-logs).
  3. Crea un utente seguendo questa guida: Creazione di un utente IAM.
  4. Seleziona l'utente creato.
  5. Seleziona la scheda Credenziali di sicurezza.
  6. Fai clic su Crea chiave di accesso nella sezione Chiavi di accesso.
  7. Seleziona Servizio di terze parti come Caso d'uso.
  8. Fai clic su Avanti.
  9. (Facoltativo) Aggiungi un tag di descrizione.
  10. Fai clic su Crea chiave di accesso.
  11. Fai clic su Scarica file CSV per salvare la chiave di accesso e la chiave di accesso segreta per un utilizzo successivo.
  12. Fai clic su Fine.
  13. Seleziona la scheda Autorizzazioni.
  14. Fai clic su Aggiungi autorizzazioni nella sezione Criteri per le autorizzazioni.
  15. Seleziona Aggiungi autorizzazioni.
  16. Seleziona Allega direttamente i criteri.
  17. Cerca e seleziona il criterio AmazonS3FullAccess.
  18. Fai clic su Avanti.
  19. Fai clic su Aggiungi autorizzazioni.

Configura il ruolo e il criterio IAM per i caricamenti S3

  1. Nella console AWS, vai a IAM > Policy > Crea policy > Scheda JSON.
  2. Inserisci la seguente policy:

    {
      "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"
        }
      ]
    }
    
    
    • Sostituisci box-collaboration-logs se hai inserito un nome bucket diverso.
  3. Fai clic su Avanti > Crea policy.

  4. Vai a IAM > Ruoli > Crea ruolo > Servizio AWS > Lambda.

  5. Allega il criterio appena creato.

  6. Assegna al ruolo il nome WriteBoxToS3Role e fai clic su Crea ruolo.

Crea la funzione Lambda

  1. Nella console AWS, vai a Lambda > Funzioni > Crea funzione.
  2. Fai clic su Crea autore da zero.
  3. Fornisci i seguenti dettagli di configurazione:

    Impostazione Valore
    Nome box_collaboration_to_s3
    Tempo di esecuzione Python 3.13
    Architettura x86_64
    Ruolo di esecuzione WriteBoxToS3Role
  4. Dopo aver creato la funzione, apri la scheda Codice, elimina lo stub e inserisci il seguente codice (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}
    
    
  5. Vai a Configurazione > Variabili di ambiente > Modifica > Aggiungi nuova variabile di ambiente.

  6. Inserisci le seguenti variabili di ambiente, sostituendole con i tuoi valori:

    Chiave Esempio
    S3_BUCKET box-collaboration-logs
    S3_PREFIX box/collaboration/
    STATE_KEY box/collaboration/state.json
    BOX_CLIENT_ID Inserisci l'ID client Box
    BOX_CLIENT_SECRET Inserisci il client secret di Box
    BOX_ENTERPRISE_ID Inserisci l'ID azienda Box
    STREAM_TYPE admin_logs_streaming
    LIMIT 500
  7. Dopo aver creato la funzione, rimani sulla relativa pagina (o apri Lambda > Funzioni > la tua funzione).

  8. Seleziona la scheda Configurazione.

  9. Nel riquadro Configurazione generale, fai clic su Modifica.

  10. Modifica Timeout impostando 10 minuti (600 secondi) e fai clic su Salva.

Pianifica la funzione Lambda (EventBridge Scheduler)

  1. Vai a Amazon EventBridge > Scheduler > Crea pianificazione.
  2. Fornisci i seguenti dettagli di configurazione:
    • Programma ricorrente: Tariffa (15 min).
    • Destinazione: la tua funzione Lambda.
    • Nome: box-collaboration-schedule-15min
  3. Fai clic su Crea pianificazione.

Configura un feed in Google SecOps per importare i log di Box

  1. Vai a Impostazioni SIEM > Feed.
  2. Fai clic su Aggiungi nuovo feed.
  3. Nel campo Nome feed, inserisci un nome per il feed (ad esempio, Box Collaboration).
  4. Seleziona Amazon S3 V2 come Tipo di origine.
  5. Seleziona Casella come Tipo di log.
  6. Fai clic su Avanti.
  7. Specifica i valori per i seguenti parametri di input:
    • URI S3: l'URI del bucket (il formato deve essere s3://box-collaboration-logs/box/collaboration/). Sostituisci box-collaboration-logs: utilizza il nome effettivo del bucket.
    • Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
    • Età massima del file: includi i file modificati nell'ultimo numero di giorni. Il valore predefinito è 180 giorni.
    • ID chiave di accesso: chiave di accesso utente con accesso al bucket S3.
    • Chiave di accesso segreta: chiave segreta dell'utente con accesso al bucket S3.
    • Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset.
    • Etichette di importazione: l'etichetta da applicare agli eventi di questo feed.
  8. Fai clic su Avanti.
  9. Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.

Tabella di mappatura UDM

Campo log Mappatura UDM Logic
additional_details.ekm_id additional.fields Valore estratto da additional_details.ekm_id
additional_details.service_id additional.fields Valore estratto da additional_details.service_id
additional_details.service_name additional.fields Valore estratto da additional_details.service_name
additional_details.shared_link_id additional.fields Valore estratto da additional_details.shared_link_id
additional_details.size target.file.size Valore estratto da additional_details.size
additional_details.version_id additional.fields Valore estratto da additional_details.version_id
created_at metadata.event_timestamp Valore tratto da created_at
created_by.id principal.user.userid Valore tratto da created_by.id
created_by.login principal.user.email_addresses Valore tratto da created_by.login
created_by.name principal.user.user_display_name Valore tratto da created_by.name
event_id metadata.product_log_id Valore estratto da event_id
event_type metadata.product_event_type Valore estratto da event_type
ip_address principal.ip Valore tratto da ip_address
source.item_id target.file.product_object_id Valore tratto da source.item_id
source.item_name target.file.full_path Valore tratto da source.item_name
source.item_type Non mappato
source.login target.user.email_addresses Valore tratto da source.login
source.name target.user.user_display_name Valore tratto da source.name
source.owned_by.id target.user.userid Valore estratto da source.owned_by.id
source.owned_by.login target.user.email_addresses Valore tratto da source.owned_by.login
source.owned_by.name target.user.user_display_name Valore tratto da source.owned_by.name
source.parent.id Non mappato
source.parent.name Non mappato
source.parent.type Non mappato
source.type Non mappato
tipo metadata.log_type Valore tratto dal tipo
metadata.vendor_name Valore hardcoded
metadata.product_name Valore hardcoded
security_result.action Derivato da event_type. Se event_type è FAILED_LOGIN, BLOCK; se event_type è USER_LOGIN, ALLOW; altrimenti UNSPECIFIED.
extensions.auth.type Derivato da event_type. Se event_type è USER_LOGIN o ADMIN_LOGIN, allora MACHINE, altrimenti UNSPECIFIED.
extensions.auth.mechanism Derivato da event_type. Se event_type è USER_LOGIN o ADMIN_LOGIN, USERNAME_PASSWORD, altrimenti UNSPECIFIED.

Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.