Collecter les journaux JSON de collaboration Box

Compatible avec :

Ce document explique comment ingérer des journaux JSON de collaboration Box dans Google Security Operations à l'aide d'AWS S3 avec la planification Lambda et EventBridge. L'analyseur traite les journaux d'événements Box au format JSON et les mappe à un modèle de données unifié (UDM). Il extrait les champs pertinents des journaux bruts, effectue des transformations de données telles que le renommage et la fusion, et enrichit les données avec des informations intermédiaires avant de générer les données d'événement structurées.

Avant de commencer

  • Instance Google SecOps
  • Accès privilégié à Box (console d'administration et console pour les développeurs)
  • Accès privilégié à AWS (S3, IAM, Lambda, EventBridge) dans la même région où vous prévoyez de stocker les journaux

Configurer la console de développement Box (identifiants client)

  1. Connectez-vous à la console Box pour les développeurs.
  2. Créez une application personnalisée avec l'authentification du serveur (attribution d'identifiants client).
  3. Définissez Application Access (Accès aux applications) sur App + Enterprise Access (Accès aux applications et à l'entreprise).
  4. Dans Application Scopes (Champs d'application de l'application), activez Manage enterprise properties (Gérer les propriétés d'entreprise).
  5. Dans la console d'administration> Applications> Gestionnaire d'applications personnalisées, autorisez l'application par ID client.
  6. Copiez et enregistrez l'ID client et le code secret du client dans un emplacement sécurisé.
  7. Accédez à la console d'administration> Compte et facturation > Informations sur le compte.
  8. Copiez l'ID d'entreprise et enregistrez-le dans un emplacement sécurisé.

Configurer un bucket AWS S3 et IAM pour Google SecOps

  1. Créez un bucket Amazon S3 en suivant ce guide de l'utilisateur : Créer un bucket.
  2. Enregistrez le nom et la région du bucket pour référence ultérieure (par exemple, box-collaboration-logs).
  3. Créez un utilisateur en suivant ce guide : Créer un utilisateur IAM.
  4. Sélectionnez l'utilisateur créé.
  5. Sélectionnez l'onglet Informations d'identification de sécurité.
  6. Cliquez sur Créer une clé d'accès dans la section Clés d'accès.
  7. Sélectionnez Service tiers comme Cas d'utilisation.
  8. Cliquez sur Suivant.
  9. Facultatif : ajoutez un tag de description.
  10. Cliquez sur Créer une clé d'accès.
  11. Cliquez sur Télécharger le fichier CSV pour enregistrer la clé d'accès et la clé d'accès secrète pour une utilisation ultérieure.
  12. Cliquez sur OK.
  13. Sélectionnez l'onglet Autorisations.
  14. Cliquez sur Ajouter des autorisations dans la section Règles d'autorisation.
  15. Sélectionnez Ajouter des autorisations.
  16. Sélectionnez Joindre directement des règles.
  17. Recherchez et sélectionnez la règle AmazonS3FullAccess.
  18. Cliquez sur Suivant.
  19. Cliquez sur Ajouter des autorisations.

Configurer la stratégie et le rôle IAM pour les importations S3

  1. Dans la console AWS, accédez à IAM > Policies > Create policy > onglet JSON.
  2. Saisissez la règle suivante :

    {
      "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"
        }
      ]
    }
    
    
    • Remplacez box-collaboration-logs si vous avez saisi un autre nom de bucket.
  3. Cliquez sur Suivant > Créer une règle.

  4. Accédez à IAM > Rôles > Créer un rôle > Service AWS > Lambda.

  5. Associez la règle que vous venez de créer.

  6. Nommez le rôle WriteBoxToS3Role, puis cliquez sur Créer un rôle.

Créer la fonction Lambda

  1. Dans la console AWS, accédez à Lambda > Fonctions > Créer une fonction.
  2. Cliquez sur Créer à partir de zéro.
  3. Fournissez les informations de configuration suivantes :

    Paramètre Valeur
    Nom box_collaboration_to_s3
    Durée d'exécution Python 3.13
    Architecture x86_64
    Rôle d'exécution WriteBoxToS3Role
  4. Une fois la fonction créée, ouvrez l'onglet Code, supprimez le stub et saisissez le code suivant (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. Accédez à Configuration> Variables d'environnement> Modifier> Ajouter une variable d'environnement.

  6. Saisissez les variables d'environnement suivantes en remplaçant les valeurs par les vôtres :

    Clé Exemple
    S3_BUCKET box-collaboration-logs
    S3_PREFIX box/collaboration/
    STATE_KEY box/collaboration/state.json
    BOX_CLIENT_ID Saisissez l'ID client Box
    BOX_CLIENT_SECRET Saisissez le code secret du client Box
    BOX_ENTERPRISE_ID Saisir l'ID Box Enterprise
    STREAM_TYPE admin_logs_streaming
    LIMIT 500
  7. Une fois la fonction créée, restez sur sa page (ou ouvrez Lambda > Fonctions > votre-fonction).

  8. Accédez à l'onglet Configuration.

  9. Dans le panneau Configuration générale, cliquez sur Modifier.

  10. Définissez Timeout sur 10 minutes (600 secondes), puis cliquez sur Save (Enregistrer).

Planifier la fonction Lambda (EventBridge Scheduler)

  1. Accédez à Amazon EventBridge> Scheduler> Create schedule (Créer une programmation).
  2. Fournissez les informations de configuration suivantes :
    • Planning récurrent : Tarif (15 min).
    • Cible : votre fonction Lambda.
    • Nom : box-collaboration-schedule-15min.
  3. Cliquez sur Créer la programmation.

Configurer un flux dans Google SecOps pour ingérer les journaux Box

  1. Accédez à Paramètres SIEM> Flux.
  2. Cliquez sur Add New Feed (Ajouter un flux).
  3. Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple, Box Collaboration).
  4. Sélectionnez Amazon S3 V2 comme type de source.
  5. Sélectionnez Box comme type de journal.
  6. Cliquez sur Suivant.
  7. Spécifiez les valeurs des paramètres d'entrée suivants :
    • URI S3 : URI du bucket (le format doit être s3://box-collaboration-logs/box/collaboration/). Remplacez box-collaboration-logs par le nom réel du bucket.
    • Options de suppression de la source : sélectionnez l'option de suppression de votre choix.
    • Âge maximal des fichiers : incluez les fichiers modifiés au cours des derniers jours. La valeur par défaut est de 180 jours.
    • ID de clé d'accès : clé d'accès utilisateur ayant accès au bucket S3.
    • Clé d'accès secrète : clé secrète de l'utilisateur ayant accès au bucket S3.
    • Espace de noms de l'élément : espace de noms de l'élément.
    • Libellés d'ingestion : libellé à appliquer aux événements de ce flux.
  8. Cliquez sur Suivant.
  9. Vérifiez la configuration de votre nouveau flux sur l'écran Finaliser, puis cliquez sur Envoyer.

Table de mappage UDM

Champ du journal Mappage UDM Logique
additional_details.ekm_id additional.fields Valeur extraite de additional_details.ekm_id
additional_details.service_id additional.fields Valeur extraite de additional_details.service_id
additional_details.service_name additional.fields Valeur extraite de additional_details.service_name
additional_details.shared_link_id additional.fields Valeur extraite de additional_details.shared_link_id
additional_details.size target.file.size Valeur extraite de additional_details.size
additional_details.version_id additional.fields Valeur extraite de additional_details.version_id
created_at metadata.event_timestamp Valeur extraite de created_at
created_by.id principal.user.userid Valeur extraite de created_by.id
created_by.login principal.user.email_addresses Valeur extraite de created_by.login
created_by.name principal.user.user_display_name Valeur extraite de created_by.name
event_id metadata.product_log_id Valeur extraite de event_id
event_type metadata.product_event_type Valeur extraite de event_type
ip_address principal.ip Valeur extraite de ip_address
source.item_id target.file.product_object_id Valeur extraite de source.item_id
source.item_name target.file.full_path Valeur extraite de source.item_name
source.item_type Non mappé
source.login target.user.email_addresses Valeur extraite de source.login
source.name target.user.user_display_name Valeur extraite de source.name
source.owned_by.id target.user.userid Valeur extraite de source.owned_by.id
source.owned_by.login target.user.email_addresses Valeur extraite de source.owned_by.login
source.owned_by.name target.user.user_display_name Valeur extraite de source.owned_by.name
source.parent.id Non mappé
source.parent.name Non mappé
source.parent.type Non mappé
source.type Non mappé
type metadata.log_type Valeur extraite du type
metadata.vendor_name Valeur codée en dur
metadata.product_name Valeur codée en dur
security_result.action Dérivé de event_type. Si event_type est FAILED_LOGIN, alors BLOCK. Si event_type est USER_LOGIN, alors ALLOW. Sinon, UNSPECIFIED.
extensions.auth.type Dérivé de event_type. Si event_type est USER_LOGIN ou ADMIN_LOGIN, la valeur est MACHINE. Sinon, elle est UNSPECIFIED.
extensions.auth.mechanism Dérivé de event_type. USERNAME_PASSWORD si event_type est USER_LOGIN ou ADMIN_LOGIN, sinon UNSPECIFIED.

Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.