Akamai Cloud Monitor-Logs erfassen
In diesem Dokument wird beschrieben, wie Sie Akamai Cloud Monitor-Logs (Load Balancer, Traffic Shaper, ADC) mit Google Cloud Storage in Google Security Operations aufnehmen. Akamai sendet JSON-Ereignisse an Ihren HTTPS-Endpunkt. Ein API Gateway- und Cloud Functions-Empfänger schreibt die Ereignisse in GCS (JSONL, gz). Der Parser wandelt die JSON-Logs in UDM um. Dabei werden Felder aus der JSON-Nutzlast extrahiert, Datentypkonvertierungen durchgeführt, Felder umbenannt, damit sie dem UDM-Schema entsprechen, und bestimmte Logik für benutzerdefinierte Felder und die URL-Erstellung berücksichtigt. Außerdem werden Fehlerbehandlung und bedingte Logik basierend auf dem Vorhandensein von Feldern berücksichtigt.
Hinweis
Prüfen Sie, ob folgende Voraussetzungen erfüllt sind:
- Eine Google SecOps-Instanz
- Ein GCP-Projekt mit aktivierter Cloud Storage API
- Berechtigungen zum Erstellen und Verwalten von GCS-Buckets
- Berechtigungen zum Verwalten von IAM-Richtlinien für GCS-Buckets
- Berechtigungen zum Erstellen von Cloud Functions, Pub/Sub-Themen und API Gateway
- Privilegierter Zugriff auf Akamai Control Center und Property Manager
Google Cloud Storage-Bucket erstellen
- Rufen Sie die Google Cloud Console auf.
- Wählen Sie Ihr Projekt aus oder erstellen Sie ein neues.
- Rufen Sie im Navigationsmenü Cloud Storage > Buckets auf.
- Klicken Sie auf Bucket erstellen.
Geben Sie die folgenden Konfigurationsdetails an:
Einstellung Wert Bucket benennen Geben Sie einen global eindeutigen Namen ein, z. B. akamai-cloud-monitor.Standorttyp Wählen Sie je nach Bedarf aus (Region, Dual-Region, Multi-Region). Standort Wählen Sie den Speicherort aus, z. B. us-central1.Speicherklasse Standard (empfohlen für Logs, auf die häufig zugegriffen wird) Zugriffssteuerung Einheitlich (empfohlen) Schutzmaßnahmen Optional: Objektversionsverwaltung oder Aufbewahrungsrichtlinie aktivieren Klicken Sie auf Erstellen.
Konfigurationsdetails für Akamai Cloud Monitor erfassen
Sie benötigen die folgenden Informationen aus dem Akamai Control Center:
- Name der Unterkunft in Property Manager
- Erforderliche Cloud Monitor-Datasets zum Erheben
- Optionaler gemeinsamer Secret-Token für die Webhook-Authentifizierung
Dienstkonto für Cloud Functions-Funktion erstellen
Für die Cloud-Funktion ist ein Dienstkonto mit Berechtigungen zum Schreiben in den GCS-Bucket erforderlich.
Dienstkonto erstellen
- Wechseln Sie in der GCP Console zu IAM & Verwaltung > Dienstkonten.
- Klicken Sie auf Dienstkonto erstellen.
- Geben Sie die folgenden Konfigurationsdetails an:
- Name des Dienstkontos: Geben Sie
akamai-cloud-monitor-saein. - Beschreibung des Dienstkontos: Geben Sie
Service account for Cloud Function to collect Akamai Cloud Monitor logsein.
- Name des Dienstkontos: Geben Sie
- Klicken Sie auf Erstellen und fortfahren.
- Im Abschnitt Diesem Dienstkonto Zugriff auf das Projekt erteilen:
- Klicken Sie auf Rolle auswählen.
- Suchen Sie nach Storage-Objekt-Administrator und wählen Sie die Rolle aus.
- Klicken Sie auf + Weitere Rolle hinzufügen.
- Suchen Sie nach Cloud Run Invoker und wählen Sie die Rolle aus.
- Klicken Sie auf + Weitere Rolle hinzufügen.
- Suchen Sie nach Cloud Functions Invoker und wählen Sie die Rolle aus.
- Klicken Sie auf Weiter.
- Klicken Sie auf Fertig.
Diese Rollen sind erforderlich für:
- Storage-Objekt-Administrator: Protokolle in GCS-Bucket schreiben und Statusdateien verwalten
- Cloud Run-Aufrufer: Pub/Sub darf die Funktion aufrufen.
- Cloud Functions-Invoker: Funktionsaufruf zulassen
IAM-Berechtigungen für GCS-Bucket erteilen
Gewähren Sie dem Dienstkonto Schreibberechtigungen für den GCS-Bucket:
- Rufen Sie Cloud Storage > Buckets auf.
- Klicken Sie auf den Namen Ihres Buckets.
- Wechseln Sie zum Tab Berechtigungen.
- Klicken Sie auf Zugriff erlauben.
- Geben Sie die folgenden Konfigurationsdetails an:
- Hauptkonten hinzufügen: Geben Sie die E-Mail-Adresse des Dienstkontos ein (z. B.
akamai-cloud-monitor-sa@PROJECT_ID.iam.gserviceaccount.com). - Rollen zuweisen: Wählen Sie Storage-Objekt-Administrator aus.
- Hauptkonten hinzufügen: Geben Sie die E-Mail-Adresse des Dienstkontos ein (z. B.
- Klicken Sie auf Speichern.
Cloud Functions-Funktion zum Empfangen von Akamai-Logs erstellen
Die Cloud-Funktion empfängt HTTP-POST-Anfragen von Akamai Cloud Monitor und schreibt Logs in GCS.
- Wechseln Sie in der GCP Console zu Cloud Functions.
- Klicken Sie auf Funktion erstellen.
Geben Sie die folgenden Konfigurationsdetails an:
Einstellung Wert Umgebung Wählen Sie 2. Generation aus. Funktionsname akamai-cloud-monitor-receiverRegion Wählen Sie die Region aus, die Ihrem GCS-Bucket entspricht (z. B. us-central1).Im Abschnitt Trigger:
- Triggertyp: Wählen Sie HTTPS aus.
- Authentifizierung: Wählen Sie Nicht authentifizierte Aufrufe zulassen aus (Akamai sendet nicht authentifizierte Anfragen).
Klicken Sie auf Speichern, um die Triggerkonfiguration zu speichern.
Maximieren Sie Laufzeit, Build, Verbindungen und Sicherheitseinstellungen.
Im Bereich Laufzeit:
- Zugewiesener Arbeitsspeicher: Wählen Sie 512 MiB aus.
- Zeitlimit: Geben Sie
600Sekunden (10 Minuten) ein. - Laufzeitdienstkonto: Wählen Sie das Dienstkonto (
akamai-cloud-monitor-sa) aus.
Klicken Sie im Bereich Laufzeit-Umgebungsvariablen für jede Variable auf + Variable hinzufügen:
Variablenname Beispielwert GCS_BUCKETakamai-cloud-monitorGCS_PREFIXakamai/cloud-monitor/jsonINGEST_TOKENrandom-shared-secret(optional)Klicken Sie auf Weiter, um zum Code-Editor zu gelangen.
Wählen Sie im Drop-down-Menü Laufzeit die Option Python 3.12 aus.
Funktionscode hinzufügen
- Geben Sie main unter Funktionseinstiegspunkt ein.
Erstellen Sie im Inline-Codeeditor zwei Dateien:
- Erste Datei: main.py::
import os import json import gzip import io import uuid import datetime as dt from google.cloud import storage import functions_framework GCS_BUCKET = os.environ.get("GCS_BUCKET") GCS_PREFIX = os.environ.get("GCS_PREFIX", "akamai/cloud-monitor/json").strip("/") + "/" INGEST_TOKEN = os.environ.get("INGEST_TOKEN") # optional shared secret storage_client = storage.Client() def _write_jsonl_gz(objs: list) -> str: """Write JSON objects to GCS as gzipped JSONL.""" timestamp = dt.datetime.utcnow() key = f"{timestamp:%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) bucket = storage_client.bucket(GCS_BUCKET) blob = bucket.blob(f"{GCS_PREFIX}{key}") blob.upload_from_file(buf, content_type="application/json", content_encoding="gzip") return f"gs://{GCS_BUCKET}/{GCS_PREFIX}{key}" def _parse_records_from_request(request) -> list: """Parse JSON records from HTTP request body.""" body = request.get_data(as_text=True) if not body: return [] 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 [] @functions_framework.http def main(request): """ Cloud Function HTTP handler for Akamai Cloud Monitor logs. Args: request: Flask request object Returns: Tuple of (response_body, status_code, headers) """ # Optional shared-secret verification via query parameter (?token=...) if INGEST_TOKEN: token = request.args.get("token") if token != INGEST_TOKEN: return ("Forbidden", 403) records = _parse_records_from_request(request) if not records: return ("No content", 204) try: gcs_key = _write_jsonl_gz(records) response = { "ok": True, "gcs_key": gcs_key, "count": len(records) } return (json.dumps(response), 200, {"Content-Type": "application/json"}) except Exception as e: print(f"Error writing to GCS: {str(e)}") return (f"Internal server error: {str(e)}", 500)- Zweite Datei: requirements.txt::
functions-framework==3.* google-cloud-storage==2.*Klicken Sie auf Bereitstellen, um die Funktion bereitzustellen.
Warten Sie, bis die Bereitstellung abgeschlossen ist (2–3 Minuten).
Rufen Sie nach der Bereitstellung den Tab Trigger auf und kopieren Sie die Trigger-URL. Sie verwenden diese URL in der Akamai-Konfiguration.
Akamai Cloud Monitor zum Senden von Logs konfigurieren
- Melden Sie sich im Akamai Control Center an.
- Öffnen Sie Ihre Property im Property Manager.
- Klicken Sie auf Regel hinzufügen > „Cloud-Verwaltung“ auswählen.
- Fügen Sie Cloud Monitor Instrumentation hinzu und wählen Sie die erforderlichen Datasets aus.
- Fügen Sie Cloud Monitor Data Delivery hinzu.
Geben Sie die folgenden Konfigurationsdetails an:
- Delivery Hostname (Hostname für die Auslieferung): Geben Sie den Hostnamen aus der Trigger-URL Ihrer Cloud Functions-Funktion ein (z. B.
us-central1-your-project.cloudfunctions.net). Pfad der Bereitstellungs-URL: Geben Sie den Pfad aus der Trigger-URL Ihrer Cloud Functions-Funktion sowie ein optionales Abfragetoken ein:
- Ohne Token:
/akamai-cloud-monitor-receiver Mit Token:
/akamai-cloud-monitor-receiver?token=<INGEST_TOKEN>Ersetzen Sie
<INGEST_TOKEN>durch den Wert, den Sie in den Umgebungsvariablen der Cloud-Funktion festgelegt haben.
- Ohne Token:
- Delivery Hostname (Hostname für die Auslieferung): Geben Sie den Hostnamen aus der Trigger-URL Ihrer Cloud Functions-Funktion ein (z. B.
Klicken Sie auf Speichern.
Klicken Sie auf Aktivieren, um die Property-Version zu aktivieren.
Google SecOps-Dienstkonto abrufen
Google SecOps verwendet ein eindeutiges Dienstkonto, um Daten aus Ihrem GCS-Bucket zu lesen. Sie müssen diesem Dienstkonto Zugriff auf Ihren Bucket gewähren.
E-Mail-Adresse des Dienstkontos abrufen
- Rufen Sie die SIEM-Einstellungen > Feeds auf.
- Klicken Sie auf Neuen Feed hinzufügen.
- Klicken Sie auf Einzelnen Feed konfigurieren.
- Geben Sie im Feld Feedname einen Namen für den Feed ein, z. B.
Akamai Cloud Monitor - GCS. - Wählen Sie Google Cloud Storage V2 als Quelltyp aus.
- Wählen Sie Akamai Cloud Monitor als Logtyp aus.
Klicken Sie auf Dienstkonto abrufen. Es wird eine eindeutige E-Mail-Adresse für das Dienstkonto angezeigt, z. B.:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comKopieren Sie diese E‑Mail-Adresse für den nächsten Schritt.
Dem Google SecOps-Dienstkonto IAM-Berechtigungen gewähren
Das Google SecOps-Dienstkonto benötigt die Rolle Storage-Objekt-Betrachter für Ihren GCS-Bucket.
- Rufen Sie Cloud Storage > Buckets auf.
- Klicken Sie auf den Namen Ihres Buckets.
- Wechseln Sie zum Tab Berechtigungen.
- Klicken Sie auf Zugriff erlauben.
- Geben Sie die folgenden Konfigurationsdetails an:
- Hauptkonten hinzufügen: Fügen Sie die E‑Mail-Adresse des Google SecOps-Dienstkontos ein.
- Rollen zuweisen: Wählen Sie Storage-Objekt-Betrachter aus.
Klicken Sie auf Speichern.
Feed in Google SecOps konfigurieren, um Akamai Cloud Monitor-Logs aufzunehmen
- Rufen Sie die SIEM-Einstellungen > Feeds auf.
- Klicken Sie auf Neuen Feed hinzufügen.
- Klicken Sie auf Einzelnen Feed konfigurieren.
- Geben Sie im Feld Feedname einen Namen für den Feed ein, z. B.
Akamai Cloud Monitor - GCS. - Wählen Sie Google Cloud Storage V2 als Quelltyp aus.
- Wählen Sie Akamai Cloud Monitor als Logtyp aus.
- Klicken Sie auf Weiter.
Geben Sie Werte für die folgenden Eingabeparameter an:
Storage-Bucket-URL: Geben Sie den GCS-Bucket-URI mit dem Präfixpfad ein:
gs://akamai-cloud-monitor/akamai/cloud-monitor/json/Ersetzen Sie:
akamai-cloud-monitor: Der Name Ihres GCS-Buckets.akamai/cloud-monitor/json: Präfixpfad, in dem Logs gespeichert werden. Muss mitGCS_PREFIXin der Cloud-Funktion übereinstimmen.
Option zum Löschen der Quelle: Wählen Sie die gewünschte Löschoption aus:
- Nie: Es werden nach Übertragungen nie Dateien gelöscht (empfohlen für Tests).
- Übertragene Dateien löschen: Dateien werden nach der erfolgreichen Übertragung gelöscht.
Übertragene Dateien und leere Verzeichnisse löschen: Löscht Dateien und leere Verzeichnisse nach der erfolgreichen Übertragung.
Maximales Dateialter: Dateien einschließen, die in den letzten Tagen geändert wurden. Der Standardwert ist 180 Tage.
Asset-Namespace:
akamai.cloud_monitorLabels für die Datenaufnahme: Alle Ereignisse aus diesem Feed werden mit Labels versehen, z. B.
source=akamai_cloud_monitorundformat=json.
Klicken Sie auf Weiter.
Prüfen Sie die neue Feedkonfiguration auf dem Bildschirm Abschließen und klicken Sie dann auf Senden.
Unterstützte Akamai Cloud Monitor-Beispiellogs
JSON:
{ "UA": "-", "accLang": "-", "bytes": "3929", "cacheStatus": "1", "cliIP": "0.0.0.0", "cookie": "-", "cp": "848064", "customField": "-", "dnsLookupTimeMSec": "-", "errorCode": "-", "maxAgeSec": "31536000", "objSize": "3929", "overheadBytes": "240", "proto": "HTTPS", "queryStr": "-", "range": "-", "referer": "-", "reqEndTimeMSec": "4", "reqHost": "www.example.com", "reqId": "1ce83c03", "reqMethod": "GET", "reqPath": "assets/images/placeholder-tagline.png", "reqPort": "443", "reqTimeSec": "1622470405.760", "rspContentLen": "3929", "rspContentType": "image/png", "statusCode": "200", "tlsOverheadTimeMSec": "0", "tlsVersion": "TLSv1.2", "totalBytes": "4599", "transferTimeMSec": "0", "turnAroundTimeMSec": "0", "uncompressedSize": "-", "version": "1", "xForwardedFor": "-" }
UDM-Zuordnungstabelle
| Logfeld | UDM-Zuordnung | Logik |
|---|---|---|
| accLang | network.http.user_agent | Direkt zugeordnet, wenn nicht „-“ oder leerer String. |
| Ort | principal.location.city | Direkt zugeordnet, wenn nicht „-“ oder leerer String. |
| cliIP | principal.ip | Direkt zugeordnet, wenn kein leerer String. |
| country | principal.location.country_or_region | Direkt zugeordnet, wenn nicht „-“ oder leerer String. |
| cp | additional.fields | Als Schlüssel/Wert-Paar mit dem Schlüssel „cp“ zugeordnet. |
| customField | about.ip, about.labels, src.ip | Als Schlüssel/Wert-Paare geparst. Sonderbehandlung von „eIp“ und „pIp“, um sie src.ip bzw. about.ip zuzuordnen. Andere Schlüssel werden als Labels im Bereich „Über“ abgebildet. |
| errorCode | security_result.summary, security_result.severity | Falls vorhanden, wird security_result.severity auf „ERROR“ gesetzt und der Wert wird security_result.summary zugeordnet. |
| geo.city | principal.location.city | Direkt zugeordnet, wenn die Stadt „-“ oder ein leerer String ist. |
| geo.country | principal.location.country_or_region | Direkt zugeordnet, wenn das Land „-“ oder ein leerer String ist. |
| geo.lat | principal.location.region_latitude | Direkt zugeordnet, in Gleitkommazahl konvertiert. |
| geo.long | principal.location.region_longitude | Direkt zugeordnet, in Gleitkommazahl konvertiert. |
| geo.region | principal.location.state | Direkt zugeordnet. |
| id | metadata.product_log_id | Direkt zugeordnet, wenn kein leerer String. |
| message.cliIP | principal.ip | Direkt zugeordnet, wenn „cliIP“ ein leerer String ist. |
| message.fwdHost | principal.hostname | Direkt zugeordnet. |
| message.reqHost | target.hostname, target.url | Wird verwendet, um „target.url“ zu erstellen und „target.hostname“ zu extrahieren. |
| message.reqLen | network.sent_bytes | Direkt zugeordnet, in eine vorzeichenlose Ganzzahl konvertiert, wenn „totalBytes“ leer oder „-“ ist. |
| message.reqMethod | network.http.method | Direkt zugeordnet, wenn „reqMethod“ ein leerer String ist. |
| message.reqPath | target.url | Wird an „target.url“ angehängt. |
| message.reqPort | target.port | Direkt zugeordnet, in eine Ganzzahl konvertiert, wenn „reqPort“ ein leerer String ist. |
| message.respLen | network.received_bytes | Direkt zugeordnet, in eine vorzeichenlose Ganzzahl konvertiert. |
| message.sslVer | network.tls.version | Direkt zugeordnet. |
| message.status | network.http.response_code | Direkt zugeordnet, in eine Ganzzahl konvertiert, wenn „statusCode“ leer oder „-“ ist. |
| message.UA | network.http.user_agent | Direkt zugeordnet, wenn UA „-“ oder ein leerer String ist. |
| network.asnum | additional.fields | Als Schlüssel/Wert-Paar mit dem Schlüssel „asnum“ zugeordnet. |
| network.edgeIP | intermediary.ip | Direkt zugeordnet. |
| network.network | additional.fields | Als Schlüssel/Wert-Paar mit dem Schlüssel „network“ zugeordnet. |
| network.networkType | additional.fields | Als Schlüssel/Wert-Paar mit dem Schlüssel „networkType“ zugeordnet. |
| proto | network.application_protocol | Wird verwendet, um „network.application_protocol“ zu bestimmen. |
| queryStr | target.url | Wird an „target.url“ angehängt, wenn es sich nicht um „-“ oder einen leeren String handelt. |
| Referrer | network.http.referral_url, about.hostname | Direkt zugeordnet, wenn nicht „-“. Der extrahierte Hostname wird „about.hostname“ zugeordnet. |
| reqHost | target.hostname, target.url | Wird verwendet, um „target.url“ zu erstellen und „target.hostname“ zu extrahieren. |
| reqId | metadata.product_log_id, network.session_id | Direkt zugeordnet, wenn die ID ein leerer String ist. Wird auch network.session_id zugeordnet. |
| reqMethod | network.http.method | Direkt zugeordnet, wenn kein leerer String. |
| reqPath | target.url | Wird an „target.url“ angehängt, wenn nicht „-“. |
| reqPort | target.port | Direkt zugeordnet, in eine Ganzzahl konvertiert. |
| reqTimeSec | metadata.event_timestamp, timestamp | Wird zum Festlegen des Zeitstempels für Ereignisse verwendet. |
| start | metadata.event_timestamp, timestamp | Wird verwendet, um den Ereigniszeitstempel festzulegen, wenn „reqTimeSec“ ein leerer String ist. |
| statusCode | network.http.response_code | Direkt zugeordnet, in eine Ganzzahl konvertiert, wenn nicht „-“ oder ein leerer String. |
| tlsVersion | network.tls.version | Direkt zugeordnet. |
| totalBytes | network.sent_bytes | Direkt zugeordnet, in eine vorzeichenlose Ganzzahl konvertiert, wenn nicht leer oder „-“. |
| Typ | metadata.product_event_type | Direkt zugeordnet. |
| UA | network.http.user_agent | Direkt zugeordnet, wenn nicht „-“ oder leerer String. |
| Version | metadata.product_version | Direkt zugeordnet. |
| xForwardedFor | principal.ip | Direkt zugeordnet, wenn nicht „-“ oder leerer String. |
| (Parserlogik) | metadata.vendor_name | Legen Sie diesen Wert auf „Akamai“ fest. |
| (Parserlogik) | metadata.product_name | Legen Sie diesen Wert auf „Cloud Monitor“ fest. |
| (Parserlogik) | metadata.event_type | Legen Sie diesen Wert auf „NETWORK_HTTP“ fest. |
| (Parserlogik) | metadata.product_version | Wird auf „2“ gesetzt, wenn die Version ein leerer String ist. |
| (Parserlogik) | metadata.log_type | Legen Sie diesen Wert auf „AKAMAI_CLOUD_MONITOR“ fest. |
| (Parserlogik) | network.application_protocol | Wird aus „proto“ oder „message.proto“ abgeleitet. Wird auf „HTTPS“ festgelegt, wenn eine der beiden Angaben „HTTPS“ (unabhängig von der Groß-/Kleinschreibung) enthält, andernfalls auf „HTTP“. |
| (Parserlogik) | security_result.severity | Auf „INFORMATIONAL“ festgelegt, wenn „errorCode“ „-“ oder ein leerer String ist. |
| (Parserlogik) | target.url | Wird aus „protocol“, „reqHost“ (oder „message.reqHost“), „reqPath“ (oder „message.reqPath“) und „queryStr“ erstellt. |
Benötigen Sie weitere Hilfe? Antworten von Community-Mitgliedern und Google SecOps-Experten erhalten