Raccogliere i log di Akamai Cloud Monitor
Questo documento spiega come importare i log di Akamai Cloud Monitor (bilanciatore del carico, Traffic Shaper, ADC) in Google Security Operations utilizzando AWS S3. Akamai invia eventi JSON al tuo endpoint HTTPS; un ricevitore API Gateway + Lambda scrive gli eventi in S3 (JSONL, gz). Il parser trasforma i log JSON in UDM. Estrae i campi dal payload JSON, esegue le conversioni dei tipi di dati, rinomina i campi in modo che corrispondano allo schema UDM e gestisce la logica specifica per i campi personalizzati e la creazione degli URL. Incorpora anche la gestione degli errori e la logica condizionale in base alla presenza dei campi.
Prima di iniziare
Assicurati di soddisfare i seguenti prerequisiti:
- Istanza Google SecOps
- Accesso con privilegi ad Akamai Control Center e Property Manager
- Accesso con privilegi ad AWS*(S3, IAM, Lambda, API Gateway)
Configura il bucket AWS S3 e IAM per Google SecOps
- Crea un bucket Amazon S3 seguendo questa guida utente: Creazione di un bucket
- Salva il nome e la regione del bucket per riferimento futuro (ad esempio,
akamai-cloud-monitor
). - Crea un utente seguendo questa guida: Creazione di un utente IAM.
- Seleziona l'utente creato.
- Seleziona la scheda Credenziali di sicurezza.
- Fai clic su Crea chiave di accesso nella sezione Chiavi di accesso.
- Seleziona Servizio di terze parti come Caso d'uso.
- Fai clic su Avanti.
- (Facoltativo) Aggiungi un tag di descrizione.
- Fai clic su Crea chiave di accesso.
- Fai clic su Scarica file CSV per salvare la chiave di accesso e la chiave di accesso segreta per un utilizzo successivo.
- Fai clic su Fine.
- Seleziona la scheda Autorizzazioni.
- Fai clic su Aggiungi autorizzazioni nella sezione Criteri per le autorizzazioni.
- Seleziona Aggiungi autorizzazioni.
- Seleziona Allega direttamente i criteri.
- Cerca e seleziona il criterio AmazonS3FullAccess.
- Fai clic su Avanti.
- Fai clic su Aggiungi autorizzazioni.
Configura il ruolo e il criterio IAM per i caricamenti S3 (Lambda)
- Nella console AWS, vai a IAM > Policy > Crea policy > JSON e incolla la policy riportata di seguito.
Policy JSON (sostituisci
akamai-cloud-monitor
con il nome del tuo bucket S3):{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPutAkamaiObjects", "Effect": "Allow", "Action": ["s3:PutObject"], "Resource": "arn:aws:s3:::akamai-cloud-monitor/*" } ] }
Fai clic su Avanti > Crea criterio.
Vai a IAM > Ruoli > Crea ruolo > Servizio AWS > Lambda.
Allega il criterio JSON.
Assegna al ruolo il nome
WriteAkamaiCMToS3Role
e fai clic su Crea ruolo.
Crea la funzione Lambda
Impostazione | Valore |
---|---|
Nome | akamai_cloud_monitor_to_s3 |
Tempo di esecuzione | Python 3.13 |
Architettura | x86_64 |
Ruolo di esecuzione | WriteAkamaiCMToS3Role |
Dopo aver creato la funzione, apri la scheda Codice, elimina lo stub e inserisci il seguente codice (
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)}), }
Vai a Configurazione > Variabili di ambiente > Modifica.
Fai clic su Aggiungi nuova variabile di ambiente e imposta i seguenti valori:
Variabili di ambiente
Chiave Esempio S3_BUCKET_NAME
akamai-cloud-monitor
S3_PREFIX
akamai/cloud-monitor/json/
INGEST_TOKEN
random-shared-secret
Vai a Configurazione > Configurazione generale.
Fai clic su Modifica e imposta Timeout su 5 minuti (300 secondi).
Fai clic su Salva.
Crea Amazon API Gateway (endpoint HTTPS per Akamai)
- Nella console AWS, vai a API Gateway > Crea API.
- Seleziona API HTTP > Build (Crea).
- Fornisci i seguenti dettagli di configurazione:
- Integrations (Integrazioni): scegli Lambda e seleziona
akamai_cloud_monitor_to_s3
. - Route: aggiungi QUALSIASI
/{proxy+}
o crea una route specifica (ad esempio, POST/akamai/cloud-monitor
). - Fasi: crea o utilizza $default.
- Integrations (Integrazioni): scegli Lambda e seleziona
- Esegui il deployment dell'API e copia l'URL di chiamata (ad esempio,
https://abc123.execute-api.<region>.amazonaws.com
).
Configura Akamai Cloud Monitor per il push dei log
- In Akamai Control Center, apri la proprietà in Property Manager.
- Fai clic su Aggiungi regola > scegli Gestione cloud.
- Aggiungi Cloud Monitor Instrumentation e seleziona i set di dati richiesti.
- Aggiungi Cloud Monitor Data Delivery.
- Nome host di pubblicazione: inserisci l'URL di chiamata dell'API Gateway (ad esempio,
abc123.execute-api.<region>.amazonaws.com
). - Percorso URL di pubblicazione: il tuo percorso più un token di query facoltativo, ad esempio:
/akamai/cloud-monitor?token=<INGEST_TOKEN>
.
- Nome host di pubblicazione: inserisci l'URL di chiamata dell'API Gateway (ad esempio,
- Salva e attiva la versione della proprietà.
Configurare un feed in Google SecOps per l'importazione di Akamai Cloud Monitor (S3 JSON)
- Vai a Impostazioni SIEM > Feed.
- Fai clic su Aggiungi nuovo feed.
- Nel campo Nome feed, inserisci un nome per il feed (ad esempio,
Akamai Cloud Monitor — S3
). - Seleziona Amazon S3 V2 come Tipo di origine.
- Seleziona Akamai Cloud Monitor come Tipo di log.
- Fai clic su Avanti.
- Specifica i valori per i seguenti parametri di input:
- URI S3:
s3://akamai-cloud-monitor/akamai/cloud-monitor/json/
- Opzioni di eliminazione dell'origine: se eliminare file e/o directory dopo il trasferimento.
- Età massima del file: include i file modificati nell'ultimo numero di giorni. Il valore predefinito è 180 giorni.
- ID chiave di accesso: una chiave di accesso all'account alfanumerica di 20 caratteri (ad es. AKIAIOSFODNN7EXAMPLE).
- Chiave di accesso segreta: una chiave di accesso segreta alfanumerica di 40 caratteri (ad es. wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY).
- Spazio dei nomi dell'asset:
akamai.cloud_monitor
- Etichette di importazione: le etichette vengono aggiunte a tutti gli eventi di questo feed (ad esempio
source=akamai_cloud_monitor
,format=json
).
- URI S3:
- Fai clic su Avanti.
- Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.
Tabella di mappatura UDM
Campo log | Mappatura UDM | Logic |
---|---|---|
accLang |
network.http.user_agent |
Mappato direttamente se non è "-" o una stringa vuota. |
city |
principal.location.city |
Mappato direttamente se non è "-" o una stringa vuota. |
cliIP |
principal.ip |
Mappato direttamente se non è una stringa vuota. |
country |
principal.location.country_or_region |
Mappato direttamente se non è "-" o una stringa vuota. |
cp |
additional.fields |
Mappato come coppia chiave-valore con la chiave "cp". |
customField |
about.ip , about.labels , src.ip |
Analizzati come coppie chiave-valore. Gestione speciale per "eIp" e "pIp" da mappare rispettivamente a src.ip e about.ip . Le altre chiavi sono mappate come etichette all'interno di about . |
errorCode |
security_result.summary , security_result.severity |
Se presente, imposta security_result.severity su "ERROR" e mappa il valore a security_result.summary . |
geo.city |
principal.location.city |
Mappato direttamente se city è "-" o una stringa vuota. |
geo.country |
principal.location.country_or_region |
Mappato direttamente se country è "-" o una stringa vuota. |
geo.lat |
principal.location.region_latitude |
Mappato direttamente, convertito in float. |
geo.long |
principal.location.region_longitude |
Mappato direttamente, convertito in float. |
geo.region |
principal.location.state |
Mappato direttamente. |
id |
metadata.product_log_id |
Mappato direttamente se non è una stringa vuota. |
message.cliIP |
principal.ip |
Mappato direttamente se cliIP è una stringa vuota. |
message.fwdHost |
principal.hostname |
Mappato direttamente. |
message.reqHost |
target.hostname , target.url |
Utilizzato per costruire target.url ed estrarre target.hostname . |
message.reqLen |
network.sent_bytes |
Mappato direttamente, convertito in numero intero senza segno se totalBytes è vuoto o "-". |
message.reqMethod |
network.http.method |
Mappato direttamente se reqMethod è una stringa vuota. |
message.reqPath |
target.url |
Aggiunto a target.url . |
message.reqPort |
target.port |
Mappato direttamente, convertito in numero intero se reqPort è una stringa vuota. |
message.respLen |
network.received_bytes |
Mappato direttamente, convertito in numero intero senza segno. |
message.sslVer |
network.tls.version |
Mappato direttamente. |
message.status |
network.http.response_code |
Mappato direttamente, convertito in numero intero se statusCode è vuoto o "-". |
message.UA |
network.http.user_agent |
Mappato direttamente se UA è "-" o una stringa vuota. |
network.asnum |
additional.fields |
Mappato come coppia chiave-valore con la chiave "asnum". |
network.edgeIP |
intermediary.ip |
Mappato direttamente. |
network.network |
additional.fields |
Mappato come coppia chiave-valore con la chiave "network". |
network.networkType |
additional.fields |
Mappato come coppia chiave-valore con la chiave "networkType". |
proto |
network.application_protocol |
Utilizzato per determinare network.application_protocol . |
queryStr |
target.url |
Aggiunto a target.url se non è "-" o una stringa vuota. |
referer |
network.http.referral_url , about.hostname |
Mappato direttamente se non è "-". Il nome host estratto è mappato a about.hostname . |
reqHost |
target.hostname , target.url |
Utilizzato per costruire target.url ed estrarre target.hostname . |
reqId |
metadata.product_log_id , network.session_id |
Mappato direttamente se id è una stringa vuota. Mappato anche a network.session_id . |
reqMethod |
network.http.method |
Mappato direttamente se non è una stringa vuota. |
reqPath |
target.url |
Aggiunto a target.url se non è "-". |
reqPort |
target.port |
Mappato direttamente, convertito in numero intero. |
reqTimeSec |
metadata.event_timestamp , timestamp |
Utilizzato per impostare il timestamp dell'evento. |
start |
metadata.event_timestamp , timestamp |
Utilizzato per impostare il timestamp dell'evento se reqTimeSec è una stringa vuota. |
statusCode |
network.http.response_code |
Mappato direttamente, convertito in numero intero se non è "-" o una stringa vuota. |
tlsVersion |
network.tls.version |
Mappato direttamente. |
totalBytes |
network.sent_bytes |
Mappato direttamente, convertito in numero intero senza segno se non è vuoto o "-". |
type |
metadata.product_event_type |
Mappato direttamente. |
UA |
network.http.user_agent |
Mappato direttamente se non è "-" o una stringa vuota. |
version |
metadata.product_version |
Mappato direttamente. |
xForwardedFor |
principal.ip |
Mappato direttamente se non è "-" o una stringa vuota. |
(Parser Logic) | metadata.vendor_name |
Impostato su "Akamai". |
(Parser Logic) | metadata.product_name |
Imposta su "DataStream". |
(Parser Logic) | metadata.event_type |
Imposta su "NETWORK_HTTP". |
(Parser Logic) | metadata.product_version |
Impostato su "2" se version è una stringa vuota. |
(Parser Logic) | metadata.log_type |
Imposta il valore su "AKAMAI_CLOUD_MONITOR". |
(Parser Logic) | network.application_protocol |
Determinato da proto o message.proto . Imposta "HTTPS" se uno dei due contiene "HTTPS" (senza distinzione tra maiuscole e minuscole), altrimenti "HTTP". |
(Parser Logic) | security_result.severity |
Imposta il valore su "INFORMATIONAL" se errorCode è "-" o una stringa vuota. |
(Parser Logic) | target.url |
Costruito a partire da protocol , reqHost (o message.reqHost ), reqPath (o message.reqPath ) e queryStr . |
Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.