Mengumpulkan log Akamai Cloud Monitor
Dokumen ini menjelaskan cara menyerap log Akamai Cloud Monitor (Load Balancer, Traffic Shaper, ADC) ke Google Security Operations menggunakan Google Cloud Storage. Akamai mengirimkan peristiwa JSON ke endpoint HTTPS Anda; penerima API Gateway + Cloud Function menulis peristiwa ke GCS (JSONL, gz). Parser mengubah log JSON menjadi UDM. Fungsi ini mengekstrak kolom dari payload JSON, melakukan konversi jenis data, mengganti nama kolom agar sesuai dengan skema UDM, dan menangani logika tertentu untuk kolom kustom dan pembuatan URL. Hal ini juga menggabungkan penanganan error dan logika bersyarat berdasarkan keberadaan kolom.
Sebelum memulai
Pastikan Anda memiliki prasyarat berikut:
- Instance Google SecOps
- Project GCP dengan Cloud Storage API diaktifkan
- Izin untuk membuat dan mengelola bucket GCS
- Izin untuk mengelola kebijakan IAM di bucket GCS
- Izin untuk membuat Cloud Functions, topik Pub/Sub, dan API Gateway
- Akses istimewa ke Akamai Control Center dan Property Manager
Membuat bucket Google Cloud Storage
- Buka Google Cloud Console.
- Pilih project Anda atau buat project baru.
- Di menu navigasi, buka Cloud Storage > Buckets.
- Klik Create bucket.
Berikan detail konfigurasi berikut:
Setelan Nilai Beri nama bucket Anda Masukkan nama yang unik secara global (misalnya, akamai-cloud-monitor)Location type Pilih berdasarkan kebutuhan Anda (Region, Dual-region, Multi-region) Lokasi Pilih lokasi (misalnya, us-central1)Kelas penyimpanan Standar (direkomendasikan untuk log yang sering diakses) Access control Seragam (direkomendasikan) Alat perlindungan Opsional: Aktifkan pembuatan versi objek atau kebijakan retensi Klik Buat.
Mengumpulkan detail konfigurasi Akamai Cloud Monitor
Anda akan memerlukan informasi berikut dari Akamai Control Center:
- Nama properti di Pengelola Properti
- Set data Cloud Monitor yang diperlukan untuk dikumpulkan
- Token rahasia bersama opsional untuk autentikasi webhook
Buat akun layanan untuk Cloud Function
Cloud Function memerlukan akun layanan dengan izin untuk menulis ke bucket GCS.
Membuat akun layanan
- Di GCP Console, buka IAM & Admin > Service Accounts.
- Klik Create Service Account.
- Berikan detail konfigurasi berikut:
- Nama akun layanan: Masukkan
akamai-cloud-monitor-sa. - Deskripsi akun layanan: Masukkan
Service account for Cloud Function to collect Akamai Cloud Monitor logs.
- Nama akun layanan: Masukkan
- Klik Create and Continue.
- Di bagian Berikan akun layanan ini akses ke project:
- Klik Pilih peran.
- Telusuri dan pilih Storage Object Admin.
- Klik + Add another role.
- Telusuri dan pilih Cloud Run Invoker.
- Klik + Add another role.
- Telusuri dan pilih Cloud Functions Invoker.
- Klik Lanjutkan.
- Klik Selesai.
Peran ini diperlukan untuk:
- Storage Object Admin: Menulis log ke bucket GCS dan mengelola file status
- Cloud Run Invoker: Mengizinkan Pub/Sub memanggil fungsi
- Cloud Functions Invoker: Mengizinkan pemanggilan fungsi
Memberikan izin IAM pada bucket GCS
Beri akun layanan izin tulis di bucket GCS:
- Buka Cloud Storage > Buckets.
- Klik nama bucket Anda.
- Buka tab Izin.
- Klik Grant access.
- Berikan detail konfigurasi berikut:
- Tambahkan prinsipal: Masukkan email akun layanan (misalnya,
akamai-cloud-monitor-sa@PROJECT_ID.iam.gserviceaccount.com). - Tetapkan peran: Pilih Storage Object Admin.
- Tambahkan prinsipal: Masukkan email akun layanan (misalnya,
- Klik Simpan.
Membuat Cloud Function untuk menerima log Akamai
Cloud Function menerima permintaan POST HTTP dari Akamai Cloud Monitor dan menulis log ke GCS.
- Di GCP Console, buka Cloud Functions.
- Klik Create function.
Berikan detail konfigurasi berikut:
Setelan Nilai Lingkungan Pilih generasi ke-2 Nama fungsi akamai-cloud-monitor-receiverWilayah Pilih region yang cocok dengan bucket GCS Anda (misalnya, us-central1)Di bagian Pemicu:
- Jenis pemicu: Pilih HTTPS.
- Authentication: Pilih Allow unauthenticated invocations (Akamai akan mengirim permintaan yang tidak diautentikasi).
Klik Simpan untuk menyimpan konfigurasi pemicu.
Perluas Runtime, build, connections and security settings.
Di bagian Runtime:
- Memori yang dialokasikan: Pilih 512 MiB.
- Waktu tunggu: Masukkan
600detik (10 menit). - Runtime service account: Pilih akun layanan (
akamai-cloud-monitor-sa).
Di bagian Runtime environment variables, klik + Add variable untuk setiap variabel:
Nama Variabel Nilai Contoh GCS_BUCKETakamai-cloud-monitorGCS_PREFIXakamai/cloud-monitor/jsonINGEST_TOKENrandom-shared-secret(opsional)Klik Berikutnya untuk melanjutkan ke editor kode.
Di dropdown Runtime, pilih Python 3.12.
Menambahkan kode fungsi
- Masukkan main di Function entry point
Di editor kode inline, buat dua file:
- File pertama: 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)- File kedua: requirements.txt:
functions-framework==3.* google-cloud-storage==2.*Klik Deploy untuk men-deploy fungsi.
Tunggu hingga deployment selesai (2-3 menit).
Setelah deployment, buka tab Pemicu dan salin URL Pemicu. Anda akan menggunakan URL ini dalam konfigurasi Akamai.
Mengonfigurasi Akamai Cloud Monitor untuk mengirimkan log
- Login ke Akamai Control Center.
- Buka Properti Anda di Pengelola Properti.
- Klik Tambahkan Aturan > pilih Pengelolaan Cloud.
- Tambahkan Cloud Monitor Instrumentation dan pilih Dataset yang diperlukan.
- Tambahkan Pengiriman Data Cloud Monitor.
Berikan detail konfigurasi berikut:
- Nama Host Pengiriman: Masukkan nama host dari URL pemicu Cloud Function Anda (misalnya,
us-central1-your-project.cloudfunctions.net). Jalur URL Pengiriman: Masukkan jalur dari URL pemicu Cloud Function Anda ditambah token kueri opsional:
- Tanpa token:
/akamai-cloud-monitor-receiver Dengan token:
/akamai-cloud-monitor-receiver?token=<INGEST_TOKEN>Ganti
<INGEST_TOKEN>dengan nilai yang Anda tetapkan di variabel lingkungan Cloud Function.
- Tanpa token:
- Nama Host Pengiriman: Masukkan nama host dari URL pemicu Cloud Function Anda (misalnya,
Klik Simpan.
Klik Aktifkan untuk mengaktifkan versi properti.
Mengambil akun layanan Google SecOps
Google SecOps menggunakan akun layanan unik untuk membaca data dari bucket GCS Anda. Anda harus memberi akun layanan ini akses ke bucket Anda.
Dapatkan email akun layanan
- Buka Setelan SIEM > Feed.
- Klik Tambahkan Feed Baru.
- Klik Konfigurasi satu feed.
- Di kolom Nama feed, masukkan nama untuk feed (misalnya,
Akamai Cloud Monitor - GCS). - Pilih Google Cloud Storage V2 sebagai Source type.
- Pilih Akamai Cloud Monitor sebagai Log type.
Klik Get Service Account. Email akun layanan yang unik akan ditampilkan, misalnya:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comSalin alamat email ini untuk digunakan di langkah berikutnya.
Memberikan izin IAM ke akun layanan Google SecOps
Akun layanan Google SecOps memerlukan peran Storage Object Viewer di bucket GCS Anda.
- Buka Cloud Storage > Buckets.
- Klik nama bucket Anda.
- Buka tab Izin.
- Klik Grant access.
- Berikan detail konfigurasi berikut:
- Add principals: Tempel email akun layanan Google SecOps.
- Tetapkan peran: Pilih Storage Object Viewer.
Klik Simpan.
Mengonfigurasi feed di Google SecOps untuk menyerap log Akamai Cloud Monitor
- Buka Setelan SIEM > Feed.
- Klik Tambahkan Feed Baru.
- Klik Konfigurasi satu feed.
- Di kolom Nama feed, masukkan nama untuk feed (misalnya,
Akamai Cloud Monitor - GCS). - Pilih Google Cloud Storage V2 sebagai Source type.
- Pilih Akamai Cloud Monitor sebagai Log type.
- Klik Berikutnya.
Tentukan nilai untuk parameter input berikut:
URL bucket penyimpanan: Masukkan URI bucket GCS dengan jalur awalan:
gs://akamai-cloud-monitor/akamai/cloud-monitor/json/Ganti:
akamai-cloud-monitor: Nama bucket GCS Anda.akamai/cloud-monitor/json: Jalur awalan tempat log disimpan (harus cocok denganGCS_PREFIXdi Cloud Function).
Opsi penghapusan sumber: Pilih opsi penghapusan sesuai preferensi Anda:
- Jangan pernah: Tidak pernah menghapus file apa pun setelah transfer (direkomendasikan untuk pengujian).
- Hapus file yang ditransfer: Menghapus file setelah transfer berhasil.
Hapus file yang ditransfer dan direktori kosong: Menghapus file dan direktori kosong setelah transfer berhasil.
Usia File Maksimum: Menyertakan file yang diubah dalam beberapa hari terakhir. Defaultnya adalah 180 hari.
Namespace aset:
akamai.cloud_monitorLabel penyerapan: Label ditambahkan ke semua peristiwa dari feed ini (misalnya,
source=akamai_cloud_monitor,format=json).
Klik Berikutnya.
Tinjau konfigurasi feed baru Anda di layar Selesaikan, lalu klik Kirim.
Log Contoh Akamai Cloud Monitor yang Didukung
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": "-" }
Tabel Pemetaan UDM
| Kolom Log | Pemetaan UDM | Logika |
|---|---|---|
| accLang | network.http.user_agent | Dipetakan secara langsung jika bukan "-" atau string kosong. |
| kota | principal.location.city | Dipetakan secara langsung jika bukan "-" atau string kosong. |
| cliIP | principal.ip | Dipetakan secara langsung jika bukan string kosong. |
| country | principal.location.country_or_region | Dipetakan secara langsung jika bukan "-" atau string kosong. |
| cp | additional.fields | Dipetakan sebagai pasangan nilai kunci dengan kunci "cp". |
| customField | about.ip, about.labels, src.ip | Diuraikan sebagai pasangan nilai kunci. Penanganan khusus untuk "eIp" dan "pIp" untuk dipetakan ke src.ip dan about.ip. Kunci lainnya dipetakan sebagai label dalam about. |
| errorCode | security_result.summary, security_result.severity | Jika ada, menetapkan security_result.severity ke "ERROR" dan memetakan nilai ke security_result.summary. |
| geo.city | principal.location.city | Dipetakan secara langsung jika kota adalah "-" atau string kosong. |
| geo.country | principal.location.country_or_region | Dipetakan secara langsung jika negara adalah "-" atau string kosong. |
| geo.lat | principal.location.region_latitude | Dipetakan secara langsung, dikonversi menjadi float. |
| geo.long | principal.location.region_longitude | Dipetakan secara langsung, dikonversi menjadi float. |
| geo.region | principal.location.state | Dipetakan secara langsung. |
| id | metadata.product_log_id | Dipetakan secara langsung jika bukan string kosong. |
| message.cliIP | principal.ip | Dipetakan secara langsung jika cliIP adalah string kosong. |
| message.fwdHost | principal.hostname | Dipetakan secara langsung. |
| message.reqHost | target.hostname, target.url | Digunakan untuk membuat target.url dan mengekstrak target.hostname. |
| message.reqLen | network.sent_bytes | Dipetakan secara langsung, dikonversi menjadi bilangan bulat tidak bertanda jika totalBytes kosong atau "-". |
| message.reqMethod | network.http.method | Dipetakan secara langsung jika reqMethod adalah string kosong. |
| message.reqPath | target.url | Ditambahkan ke target.url. |
| message.reqPort | target.port | Dipetakan secara langsung, dikonversi menjadi bilangan bulat jika reqPort adalah string kosong. |
| message.respLen | network.received_bytes | Dipetakan secara langsung, dikonversi menjadi bilangan bulat tidak bertanda. |
| message.sslVer | network.tls.version | Dipetakan secara langsung. |
| message.status | network.http.response_code | Dipetakan secara langsung, dikonversi menjadi bilangan bulat jika statusCode kosong atau "-". |
| message.UA | network.http.user_agent | Dipetakan secara langsung jika UA adalah "-" atau string kosong. |
| network.asnum | additional.fields | Dipetakan sebagai pasangan nilai kunci dengan kunci "asnum". |
| network.edgeIP | intermediary.ip | Dipetakan secara langsung. |
| network.network | additional.fields | Dipetakan sebagai pasangan nilai kunci dengan kunci "network". |
| network.networkType | additional.fields | Dipetakan sebagai pasangan nilai kunci dengan kunci "networkType". |
| proto | network.application_protocol | Digunakan untuk menentukan network.application_protocol. |
| queryStr | target.url | Ditambahkan ke target.url jika bukan "-" atau string kosong. |
| perujuk | network.http.referral_url, about.hostname | Dipetakan secara langsung jika bukan "-". Nama host yang diekstrak dipetakan ke about.hostname. |
| reqHost | target.hostname, target.url | Digunakan untuk membuat target.url dan mengekstrak target.hostname. |
| reqId | metadata.product_log_id, network.session_id | Dipetakan secara langsung jika id adalah string kosong. Juga dipetakan ke network.session_id. |
| reqMethod | network.http.method | Dipetakan secara langsung jika bukan string kosong. |
| reqPath | target.url | Ditambahkan ke target.url jika bukan "-". |
| reqPort | target.port | Dipetakan langsung, dikonversi menjadi bilangan bulat. |
| reqTimeSec | metadata.event_timestamp, timestamp | Digunakan untuk menyetel stempel waktu peristiwa. |
| mulai | metadata.event_timestamp, timestamp | Digunakan untuk menyetel stempel waktu peristiwa jika reqTimeSec adalah string kosong. |
| statusCode | network.http.response_code | Dipetakan secara langsung, dikonversi menjadi bilangan bulat jika bukan "-" atau string kosong. |
| tlsVersion | network.tls.version | Dipetakan secara langsung. |
| totalBytes | network.sent_bytes | Dipetakan secara langsung, dikonversi menjadi bilangan bulat tidak bertanda jika tidak kosong atau "-". |
| jenis | metadata.product_event_type | Dipetakan secara langsung. |
| UA | network.http.user_agent | Dipetakan secara langsung jika bukan "-" atau string kosong. |
| versi | metadata.product_version | Dipetakan secara langsung. |
| xForwardedFor | principal.ip | Dipetakan secara langsung jika bukan "-" atau string kosong. |
| (Logika Parser) | metadata.vendor_name | Ditetapkan ke "Akamai". |
| (Logika Parser) | metadata.product_name | Setel ke "Cloud Monitor". |
| (Logika Parser) | metadata.event_type | Disetel ke "NETWORK_HTTP". |
| (Logika Parser) | metadata.product_version | Ditetapkan ke "2" jika versi adalah string kosong. |
| (Logika Parser) | metadata.log_type | Tetapkan ke "AKAMAI_CLOUD_MONITOR". |
| (Logika Parser) | network.application_protocol | Ditentukan dari proto atau message.proto. Disetel ke "HTTPS" jika salah satunya berisi "HTTPS" (tidak peka huruf besar/kecil), "HTTP" jika tidak. |
| (Logika Parser) | security_result.severity | Ditetapkan ke "INFORMATIONAL" jika errorCode adalah "-" atau string kosong. |
| (Logika Parser) | target.url | Dibuat dari protokol, reqHost (atau message.reqHost), reqPath (atau message.reqPath), dan queryStr. |
Perlu bantuan lebih lanjut? Dapatkan jawaban dari anggota Komunitas dan profesional Google SecOps.