Collecter les journaux Akamai Cloud Monitor

Compatible avec :

Ce document explique comment ingérer les journaux Akamai Cloud Monitor (Load Balancer, Traffic Shaper, ADC) dans Google Security Operations à l'aide d'AWS S3. Akamai envoie des événements JSON à votre point de terminaison HTTPS. Un récepteur API Gateway + Lambda écrit les événements dans S3 (JSONL, gz). L'analyseur transforme les journaux JSON en UDM. Il extrait les champs de la charge utile JSON, effectue des conversions de type de données, renomme les champs pour qu'ils correspondent au schéma UDM et gère la logique spécifique pour les champs personnalisés et la construction d'URL. Il intègre également la gestion des exceptions et la logique conditionnelle en fonction de la présence des champs.

Avant de commencer

Assurez-vous de remplir les conditions suivantes :

  • Instance Google SecOps
  • Accès privilégié à Akamai Control Center et Property Manager
  • Accès privilégié à AWS*(S3, IAM, Lambda, API Gateway)

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, akamai-cloud-monitor).
  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 (Lambda)

  1. Dans la console AWS, accédez à IAM > Stratégies > Créer une stratégie > JSON, puis collez la stratégie ci-dessous.
  2. Règle JSON (remplacez akamai-cloud-monitor par le nom de votre bucket S3) :

    {
    "Version": "2012-10-17",
    "Statement": [
        {
        "Sid": "AllowPutAkamaiObjects",
        "Effect": "Allow",
        "Action": ["s3:PutObject"],
        "Resource": "arn:aws:s3:::akamai-cloud-monitor/*"
        }
    ]
    }
    
  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 stratégie JSON.

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

Créer la fonction Lambda

Paramètre Valeur
Nom akamai_cloud_monitor_to_s3
Durée d'exécution Python 3.13
Architecture x86_64
Rôle d'exécution WriteAkamaiCMToS3Role
  1. Une fois la fonction créée, ouvrez l'onglet Code, supprimez le stub et saisissez le code suivant (akamai_cloud_monitor_to_s3.py) :

    #!/usr/bin/env python3
    # Lambda: Receive Akamai Cloud Monitor POST, write JSONL (gz) to S3
    
    import os, json, gzip, io, uuid, base64, datetime as dt
    import boto3
    
    S3_BUCKET  = os.environ["S3_BUCKET_NAME"]
    S3_PREFIX  = os.environ.get("S3_PREFIX", "akamai/cloud-monitor/json/").strip("/") + "/"
    INGEST_TOKEN = os.environ.get("INGEST_TOKEN")  # optional shared secret in URL query (?token=...)
    
    s3 = boto3.client("s3")
    
    def _write_jsonl_gz(objs: list) -> str:
        key = f"{dt.datetime.utcnow():%Y/%m/%d}/akamai-cloud-monitor-{uuid.uuid4()}.json.gz"
        buf = io.BytesIO()
        with gzip.GzipFile(fileobj=buf, mode="w") as gz:
            for o in objs:
                gz.write((json.dumps(o, separators=(",", ":")) + "n").encode())
        buf.seek(0)
        s3.upload_fileobj(
            buf,
            S3_BUCKET,
            f"{S3_PREFIX}{key}",
            ExtraArgs={
                "ContentType": "application/json",
                "ContentEncoding": "gzip",
            },
        )
        return f"s3://{S3_BUCKET}/{S3_PREFIX}{key}"
    
    def _parse_records_from_event(event) -> list:
        # HTTP API (Lambda proxy) event: body is a JSON string
        body = event.get("body") or ""
        if event.get("isBase64Encoded"):
            body = base64.b64decode(body).decode("utf-8", "replace")
        try:
            data = json.loads(body)
        except Exception:
            # accept line-delimited JSON as pass-through
            try:
                return [json.loads(line) for line in body.splitlines() if line.strip()]
            except Exception:
                return []
        if isinstance(data, list):
            return data
        if isinstance(data, dict):
            return [data]
        return []
    
    def lambda_handler(event, context=None):
        # Optional shared-secret verification via query parameter (?token=...)
        if INGEST_TOKEN:
            qs = event.get("queryStringParameters") or {}
            token = qs.get("token")
            if token != INGEST_TOKEN:
                return {"statusCode": 403, "body": "forbidden"}
    
        records = _parse_records_from_event(event)
        if not records:
            return {"statusCode": 204, "body": "no content"}
    
        key = _write_jsonl_gz(records)
        return {
            "statusCode": 200,
            "headers": {"Content-Type": "application/json"},
            "body": json.dumps({"ok": True, "s3_key": key, "count": len(records)}),
        }
    
  2. Accédez à Configuration > Variables d'environnement > Modifier.

  3. Cliquez sur Ajouter une variable d'environnement, puis définissez les valeurs suivantes :

    Variables d'environnement

    Clé Exemple
    S3_BUCKET_NAME akamai-cloud-monitor
    S3_PREFIX akamai/cloud-monitor/json/
    INGEST_TOKEN random-shared-secret
  4. Accédez à Configuration > Configuration générale.

  5. Cliquez sur Modifier et définissez Délai avant expiration sur 5 minutes (300 secondes).

  6. Cliquez sur Enregistrer.

Créer une passerelle Amazon API (point de terminaison HTTPS pour Akamai)

  1. Dans la console AWS, accédez à API Gateway > Créer une API.
  2. Sélectionnez API HTTP > Créer.
  3. Fournissez les informations de configuration suivantes :
    • Integrations (Intégrations) : sélectionnez Lambda, puis akamai_cloud_monitor_to_s3.
    • Routes : ajoutez ANY /{proxy+} ou créez une route spécifique (par exemple, POST /akamai/cloud-monitor).
    • Étapes : créez ou utilisez $default.
  4. Déployez l'API et copiez l'URL d'appel (par exemple, https://abc123.execute-api.<region>.amazonaws.com).

Configurer Akamai Cloud Monitor pour envoyer des journaux

  1. Dans Akamai Control Center, ouvrez votre propriété dans Property Manager.
  2. Cliquez sur Ajouter une règle> choisissez Gestion du cloud.
  3. Ajoutez Instrumentation Cloud Monitoring et sélectionnez les ensembles de données requis.
  4. Ajoutez Cloud Monitor Data Delivery.
    • Nom d'hôte de la diffusion : saisissez l'URL d'appel de la passerelle API (par exemple, abc123.execute-api.<region>.amazonaws.com).
    • Chemin d'URL de diffusion : votre route plus un jeton de requête facultatif, par exemple /akamai/cloud-monitor?token=<INGEST_TOKEN>.
  5. Enregistrez et activez la version de la propriété.

Configurer un flux dans Google SecOps pour ingérer Akamai Cloud Monitor (S3 JSON)

  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, Akamai Cloud Monitor — S3).
  4. Sélectionnez Amazon S3 V2 comme type de source.
  5. Sélectionnez Akamai Cloud Monitor comme type de journal.
  6. Cliquez sur Suivant.
  7. Spécifiez les valeurs des paramètres d'entrée suivants :
    • URI S3 : s3://akamai-cloud-monitor/akamai/cloud-monitor/json/
    • Options de suppression de la source : indiquez si vous souhaitez supprimer les fichiers et/ou les répertoires après le transfert.
    • Âge maximal du fichier : inclut 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 au compte alphanumérique de 20 caractères (par exemple, AKIAIOSFODNN7EXAMPLE).
    • Clé d'accès secrète : clé d'accès secrète alphanumérique de 40 caractères (par exemple, wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY).
    • Espace de noms de l'asset : akamai.cloud_monitor
    • Étiquettes d'ingestion : des étiquettes sont ajoutées à tous les événements de ce flux (par exemple, source=akamai_cloud_monitor, format=json).
  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 de journal Mappage UDM Logique
accLang network.http.user_agent Mappé directement s'il n'est pas "-" ou une chaîne vide.
city principal.location.city Mappé directement s'il n'est pas "-" ou une chaîne vide.
cliIP principal.ip Mappé directement s'il ne s'agit pas d'une chaîne vide.
country principal.location.country_or_region Mappé directement s'il n'est pas "-" ou une chaîne vide.
cp additional.fields Mappé sous forme de paire clé/valeur avec la clé "cp".
customField about.ip, about.labels, src.ip Analysé sous forme de paires clé-valeur. Gestion spéciale pour "eIp" et "pIp" à mapper respectivement sur src.ip et about.ip. Les autres clés sont mappées en tant que libellés dans about.
errorCode security_result.summary, security_result.severity Si ce paramètre est présent, il définit security_result.severity sur "ERROR" et mappe la valeur sur security_result.summary.
geo.city principal.location.city Mappé directement si city est "-" ou une chaîne vide.
geo.country principal.location.country_or_region Mappé directement si country est "-" ou une chaîne vide.
geo.lat principal.location.region_latitude Mappé directement, converti en float.
geo.long principal.location.region_longitude Mappé directement, converti en float.
geo.region principal.location.state Mappé directement.
id metadata.product_log_id Mappé directement s'il ne s'agit pas d'une chaîne vide.
message.cliIP principal.ip Mappé directement si cliIP est une chaîne vide.
message.fwdHost principal.hostname Mappé directement.
message.reqHost target.hostname, target.url Permet de construire target.url et d'extraire target.hostname.
message.reqLen network.sent_bytes Mappé directement, converti en entier non signé si totalBytes est vide ou "-".
message.reqMethod network.http.method Mappé directement si reqMethod est une chaîne vide.
message.reqPath target.url Ajouté à target.url.
message.reqPort target.port Mappé directement, converti en entier si reqPort est une chaîne vide.
message.respLen network.received_bytes Mappé directement, converti en entier non signé.
message.sslVer network.tls.version Mappé directement.
message.status network.http.response_code Mappé directement, converti en entier si statusCode est vide ou "-".
message.UA network.http.user_agent Mappé directement si UA est "-" ou une chaîne vide.
network.asnum additional.fields Mappé sous forme de paire clé-valeur avec la clé "asnum".
network.edgeIP intermediary.ip Mappé directement.
network.network additional.fields Mappé sous forme de paire clé-valeur avec la clé "network".
network.networkType additional.fields Mappé sous forme de paire clé-valeur avec la clé "networkType".
proto network.application_protocol Utilisé pour déterminer network.application_protocol.
queryStr target.url Ajouté à target.url si la valeur n'est pas "-" ou une chaîne vide.
referer network.http.referral_url, about.hostname Mappé directement si la valeur n'est pas "-". Le nom d'hôte extrait est mappé sur about.hostname.
reqHost target.hostname, target.url Permet de construire target.url et d'extraire target.hostname.
reqId metadata.product_log_id, network.session_id Mappé directement si id est une chaîne vide. Également mappé sur network.session_id.
reqMethod network.http.method Mappé directement s'il ne s'agit pas d'une chaîne vide.
reqPath target.url Ajouté à target.url si la valeur n'est pas "-".
reqPort target.port Mappé directement, converti en entier.
reqTimeSec metadata.event_timestamp, timestamp Permet de définir le code temporel de l'événement.
start metadata.event_timestamp, timestamp Permet de définir l'horodatage de l'événement si reqTimeSec est une chaîne vide.
statusCode network.http.response_code Mappé directement, converti en entier si la valeur n'est pas "-" ou une chaîne vide.
tlsVersion network.tls.version Mappé directement.
totalBytes network.sent_bytes Mappé directement, converti en entier non signé s'il n'est pas vide ou "-".
type metadata.product_event_type Mappé directement.
UA network.http.user_agent Mappé directement s'il n'est pas "-" ou une chaîne vide.
version metadata.product_version Mappé directement.
xForwardedFor principal.ip Mappé directement s'il n'est pas "-" ou une chaîne vide.
(Logique de l'analyseur) metadata.vendor_name Défini sur "Akamai".
(Logique de l'analyseur) metadata.product_name Définissez-le sur "DataStream".
(Logique de l'analyseur) metadata.event_type Définissez-le sur "NETWORK_HTTP".
(Logique de l'analyseur) metadata.product_version Définissez sur "2" si version est une chaîne vide.
(Logique de l'analyseur) metadata.log_type Défini sur "AKAMAI_CLOUD_MONITOR".
(Logique de l'analyseur) network.application_protocol Déterminé à partir de proto ou message.proto. Définissez sur "HTTPS" si l'une des valeurs contient "HTTPS" (sans tenir compte de la casse), ou sur "HTTP" dans le cas contraire.
(Logique de l'analyseur) security_result.severity Définissez sur "INFORMATIONAL" si errorCode est "-" ou une chaîne vide.
(Logique de l'analyseur) target.url Construit à partir de protocol, reqHost (ou message.reqHost), reqPath (ou message.reqPath) et queryStr.

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