Mengumpulkan log Symantec WSS
Dokumen ini menjelaskan cara menyerap log Symantec Web Security Service (WSS) ke Google Security Operations menggunakan Amazon S3. Pengurai pertama-tama mencoba mengurai pesan log sebagai JSON. Jika gagal, alat ini akan menggunakan serangkaian pola grok yang semakin spesifik untuk mengekstrak kolom dari teks mentah, yang pada akhirnya memetakan data yang diekstrak ke Model Data Terpadu (UDM).
Sebelum memulai
Pastikan Anda memenuhi prasyarat berikut:
- Instance Google SecOps.
- Akses istimewa ke Symantec Web Security Service.
- Akses istimewa ke AWS (S3, Identity and Access Management (IAM), Lambda, EventBridge).
Kumpulkan prasyarat Symantec WSS (ID, kunci API, ID org, token)
- Login ke Symantec Web Security Service Portal sebagai administrator.
- Buka Account > API Credentials.
- Klik Tambahkan.
- Berikan detail konfigurasi berikut:
- Nama API: Masukkan nama deskriptif (misalnya,
Google SecOps Integration
). - Deskripsi: Masukkan deskripsi untuk kredensial API.
- Nama API: Masukkan nama deskriptif (misalnya,
- Klik Simpan dan salin kredensial API yang dibuat dengan aman.
- Catat URL Portal WSS dan endpoint Sync API Anda.
- Salin dan simpan detail berikut di lokasi yang aman:
- WSS_API_USERNAME.
- WSS_API_PASSWORD.
- WSS_SYNC_URL.
Mengonfigurasi bucket AWS S3 dan IAM untuk Google SecOps
- Buat bucket Amazon S3 dengan mengikuti panduan pengguna ini: Membuat bucket
- Simpan Name dan Region bucket untuk referensi di masa mendatang (misalnya,
symantec-wss-logs
). - Buat Pengguna dengan mengikuti panduan pengguna ini: Membuat pengguna IAM.
- Pilih Pengguna yang dibuat.
- Pilih tab Kredensial keamanan.
- Klik Create Access Key di bagian Access Keys.
- Pilih Layanan pihak ketiga sebagai Kasus penggunaan.
- Klik Berikutnya.
- Opsional: Tambahkan tag deskripsi.
- Klik Create access key.
- Klik Download CSV file untuk menyimpan Access Key dan Secret Access Key untuk referensi di masa mendatang.
- Klik Selesai.
- Pilih tab Permissions.
- Klik Tambahkan izin di bagian Kebijakan izin.
- Pilih Tambahkan izin.
- Pilih Lampirkan kebijakan secara langsung.
- Cari kebijakan AmazonS3FullAccess.
- Pilih kebijakan.
- Klik Berikutnya.
- Klik Add permissions.
Mengonfigurasi kebijakan dan peran IAM untuk upload S3
- Di konsol AWS, buka IAM > Policies.
- Klik Buat kebijakan > tab JSON.
- Salin dan tempel kebijakan berikut.
Policy JSON (ganti
symantec-wss-logs
jika Anda memasukkan nama bucket yang berbeda):{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPutObjects", "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::symantec-wss-logs/*" }, { "Sid": "AllowGetStateObject", "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::symantec-wss-logs/symantec/wss/state.json" } ] }
Klik Berikutnya > Buat kebijakan.
Buka IAM > Roles > Create role > AWS service > Lambda.
Lampirkan kebijakan yang baru dibuat.
Beri nama peran
SymantecWssToS3Role
, lalu klik Buat peran.
Buat fungsi Lambda
- Di Konsol AWS, buka Lambda > Functions > Create function.
- Klik Buat dari awal.
Berikan detail konfigurasi berikut:
Setelan Nilai Nama symantec_wss_to_s3
Runtime Python 3.13 Arsitektur x86_64 Peran eksekusi SymantecWssToS3Role
Setelah fungsi dibuat, buka tab Code, hapus stub, dan tempelkan kode berikut (
symantec_wss_to_s3.py
).#!/usr/bin/env python3 # Lambda: Pull Symantec WSS logs and store raw payloads to S3 # - Time window via millisecond timestamps for WSS Sync API. # - Preserves vendor-native format (CSV/JSON/ZIP). # - Retries with exponential backoff; unique S3 keys to avoid overwrites. import os, json, time, uuid from urllib.request import Request, urlopen from urllib.error import URLError, HTTPError import boto3 S3_BUCKET = os.environ["S3_BUCKET"] S3_PREFIX = os.environ.get("S3_PREFIX", "symantec/wss/") STATE_KEY = os.environ.get("STATE_KEY", "symantec/wss/state.json") WINDOW_SEC = int(os.environ.get("WINDOW_SECONDS", "3600")) # default 1h HTTP_TIMEOUT= int(os.environ.get("HTTP_TIMEOUT", "60")) WSS_SYNC_URL = os.environ.get("WSS_SYNC_URL", "https://portal.threatpulse.com/reportpod/logs/sync") API_USERNAME = os.environ["WSS_API_USERNAME"] API_PASSWORD = os.environ["WSS_API_PASSWORD"] TOKEN_PARAM = os.environ.get("WSS_TOKEN_PARAM", "none") MAX_RETRIES = int(os.environ.get("MAX_RETRIES", "3")) USER_AGENT = os.environ.get("USER_AGENT", "symantec-wss-to-s3/1.0") s3 = boto3.client("s3") def _load_state(): try: obj = s3.get_object(Bucket=S3_BUCKET, Key=STATE_KEY) return json.loads(obj["Body"].read()) except Exception: return {} def _save_state(st): s3.put_object( Bucket=S3_BUCKET, Key=STATE_KEY, Body=json.dumps(st, separators=(",", ":")).encode("utf-8"), ContentType="application/json", ) def _ms_timestamp(ts: float) -> int: """Convert Unix timestamp to milliseconds for WSS API""" return int(ts * 1000) def _fetch_wss_logs(start_ms: int, end_ms: int) -> tuple[bytes, str, str]: # WSS Sync API parameters params = f"startDate={start_ms}&endDate={end_ms}&token={TOKEN_PARAM}" url = f"{WSS_SYNC_URL}?{params}" attempt = 0 while True: req = Request(url, method="GET") req.add_header("User-Agent", USER_AGENT) req.add_header("X-APIUsername", API_USERNAME) req.add_header("X-APIPassword", API_PASSWORD) try: with urlopen(req, timeout=HTTP_TIMEOUT) as r: blob = r.read() content_type = r.headers.get("Content-Type", "application/octet-stream") content_encoding = r.headers.get("Content-Encoding", "") return blob, content_type, content_encoding except (HTTPError, URLError) as e: attempt += 1 print(f"HTTP error on attempt {attempt}: {e}") if attempt > MAX_RETRIES: raise # exponential backoff with jitter time.sleep(min(60, 2 ** attempt) + (time.time() % 1)) def _determine_extension(content_type: str, content_encoding: str) -> str: """Determine file extension based on content type and encoding""" if "zip" in content_type.lower(): return ".zip" if "gzip" in content_type.lower() or content_encoding.lower() == "gzip": return ".gz" if "json" in content_type.lower(): return ".json" if "csv" in content_type.lower(): return ".csv" return ".bin" def _put_wss_data(blob: bytes, content_type: str, content_encoding: str, from_ts: float, to_ts: float) -> str: # Create unique S3 key for WSS data ts_path = time.strftime("%Y/%m/%d", time.gmtime(to_ts)) uniq = f"{int(time.time()*1e6)}_{uuid.uuid4().hex[:8]}" ext = _determine_extension(content_type, content_encoding) key = f"{S3_PREFIX}{ts_path}/symantec_wss_{int(from_ts)}_{int(to_ts)}_{uniq}{ext}" s3.put_object( Bucket=S3_BUCKET, Key=key, Body=blob, ContentType=content_type, Metadata={ 'source': 'symantec-wss', 'from_timestamp': str(int(from_ts)), 'to_timestamp': str(int(to_ts)), 'content_encoding': content_encoding } ) return key def lambda_handler(event=None, context=None): st = _load_state() now = time.time() from_ts = float(st.get("last_to_ts") or (now - WINDOW_SEC)) to_ts = now # Convert to milliseconds for WSS API start_ms = _ms_timestamp(from_ts) end_ms = _ms_timestamp(to_ts) print(f"Fetching Symantec WSS logs from {start_ms} to {end_ms}") blob, content_type, content_encoding = _fetch_wss_logs(start_ms, end_ms) print(f"Retrieved {len(blob)} bytes with content-type: {content_type}") if content_encoding: print(f"Content encoding: {content_encoding}") key = _put_wss_data(blob, content_type, content_encoding, from_ts, to_ts) st["last_to_ts"] = to_ts st["last_successful_run"] = now _save_state(st) return { "statusCode": 200, "body": { "success": True, "s3_key": key, "content_type": content_type, "content_encoding": content_encoding, "from_timestamp": from_ts, "to_timestamp": to_ts, "bytes_retrieved": len(blob) } } if __name__ == "__main__": print(lambda_handler())
Buka Configuration > Environment variables.
Klik Edit > Tambahkan variabel lingkungan baru.
Masukkan variabel lingkungan yang diberikan dalam tabel berikut, ganti dengan nilai contoh menggunakan nilai Anda.
Variabel lingkungan
Kunci Nilai contoh S3_BUCKET
symantec-wss-logs
S3_PREFIX
symantec/wss/
STATE_KEY
symantec/wss/state.json
WINDOW_SECONDS
3600
HTTP_TIMEOUT
60
MAX_RETRIES
3
USER_AGENT
symantec-wss-to-s3/1.0
WSS_SYNC_URL
https://portal.threatpulse.com/reportpod/logs/sync
WSS_API_USERNAME
your-api-username
(dari langkah 2)WSS_API_PASSWORD
your-api-password
(dari langkah 2)WSS_TOKEN_PARAM
none
Setelah fungsi dibuat, tetap buka halamannya (atau buka Lambda > Functions > your-function).
Pilih tab Configuration
Di panel Konfigurasi umum, klik Edit.
Ubah Waktu Tunggu menjadi 5 menit (300 detik), lalu klik Simpan.
Membuat jadwal EventBridge
- Buka Amazon EventBridge > Scheduler > Create schedule.
- Berikan detail konfigurasi berikut:
- Jadwal berulang: Tarif (
1 hour
). - Target: Fungsi Lambda Anda
symantec_wss_to_s3
. - Name:
symantec-wss-1h
.
- Jadwal berulang: Tarif (
- Klik Buat jadwal.
(Opsional) Buat pengguna dan kunci IAM hanya baca untuk Google SecOps
- Di AWS Console, buka IAM > Users.
- Klik Add users.
- Berikan detail konfigurasi berikut:
- Pengguna: Masukkan
secops-reader
. - Jenis akses: Pilih Kunci akses – Akses terprogram.
- Pengguna: Masukkan
- Klik Buat pengguna.
- Lampirkan kebijakan baca minimal (kustom): Pengguna > secops-reader > Izin > Tambahkan izin > Lampirkan kebijakan secara langsung > Buat kebijakan.
JSON:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::symantec-wss-logs/*" }, { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::symantec-wss-logs" } ] }
Nama =
secops-reader-policy
.Klik Buat kebijakan > cari/pilih > Berikutnya > Tambahkan izin.
Buat kunci akses untuk
secops-reader
: Kredensial keamanan > Kunci akses.Klik Create access key.
Download CSV. (Anda akan menempelkan nilai ini ke feed).
Mengonfigurasi feed di Google SecOps untuk menyerap log Symantec WSS
- Buka Setelan SIEM > Feed.
- Klik + Tambahkan Feed Baru.
- Di kolom Nama feed, masukkan nama untuk feed (misalnya,
Symantec WSS logs
). - Pilih Amazon S3 V2 sebagai Jenis sumber.
- Pilih Symantec WSS sebagai Jenis log.
- Klik Berikutnya.
- Tentukan nilai untuk parameter input berikut:
- URI S3:
s3://symantec-wss-logs/symantec/wss/
- Opsi penghapusan sumber: Pilih opsi penghapusan sesuai preferensi Anda.
- Usia File Maksimum: Menyertakan file yang diubah dalam jumlah hari terakhir. Defaultnya adalah 180 hari.
- ID Kunci Akses: Kunci akses pengguna dengan akses ke bucket S3.
- Kunci Akses Rahasia: Kunci rahasia pengguna dengan akses ke bucket S3.
- Namespace aset: Namespace aset.
- Label penyerapan: Label yang diterapkan ke peristiwa dari feed ini.
- URI S3:
- Klik Berikutnya.
- Tinjau konfigurasi feed baru Anda di layar Selesaikan, lalu klik Kirim.
Tabel pemetaan UDM
Kolom log | Pemetaan UDM | Logika |
---|---|---|
category_id | read_only_udm.metadata.product_event_type | Jika category_id adalah 1, maka read_only_udm.metadata.product_event_type ditetapkan ke Security . Jika category_id adalah 5, maka read_only_udm.metadata.product_event_type ditetapkan ke Policy |
collector_device_ip | read_only_udm.principal.ip, read_only_udm.principal.asset.ip | Nilai kolom collector_device_ip |
connection.bytes_download | read_only_udm.network.received_bytes | Nilai kolom connection.bytes_download dikonversi menjadi bilangan bulat |
connection.bytes_upload | read_only_udm.network.sent_bytes | Nilai kolom connection.bytes_upload dikonversi menjadi bilangan bulat |
connection.dst_ip | read_only_udm.target.ip | Nilai kolom connection.dst_ip |
connection.dst_location.country | read_only_udm.target.location.country_or_region | Nilai kolom connection.dst_location.country |
connection.dst_name | read_only_udm.target.hostname | Nilai kolom connection.dst_name |
connection.dst_port | read_only_udm.target.port | Nilai kolom connection.dst_port dikonversi menjadi bilangan bulat |
connection.http_status | read_only_udm.network.http.response_code | Nilai kolom connection.http_status dikonversi menjadi bilangan bulat |
connection.http_user_agent | read_only_udm.network.http.user_agent | Nilai kolom connection.http_user_agent |
connection.src_ip | read_only_udm.principal.ip, read_only_udm.src.ip | Nilai kolom connection.src_ip. Jika src_ip atau collector_device_ip tidak kosong, maka akan dipetakan ke read_only_udm.src.ip |
connection.tls.version | read_only_udm.network.tls.version_protocol | Nilai kolom connection.tls.version |
connection.url.host | read_only_udm.target.hostname | Nilai kolom connection.url.host |
connection.url.method | read_only_udm.network.http.method | Nilai kolom connection.url.method |
connection.url.path | read_only_udm.target.url | Nilai kolom connection.url.path |
connection.url.text | read_only_udm.target.url | Nilai kolom connection.url.text |
cs_connection_negotiated_cipher | read_only_udm.network.tls.cipher | Nilai kolom cs_connection_negotiated_cipher |
cs_icap_status | read_only_udm.security_result.description | Nilai kolom cs_icap_status |
device_id | read_only_udm.target.resource.id, read_only_udm.target.resource.product_object_id | Nilai kolom device_id |
device_ip | read_only_udm.intermediary.ip, read_only_udm.intermediary.asset.ip | Nilai kolom device_ip |
device_time | read_only_udm.metadata.collected_timestamp, read_only_udm.metadata.event_timestamp | Nilai kolom device_time dikonversi menjadi string. Jika when kosong, maka dipetakan ke read_only_udm.metadata.event_timestamp |
hostname | read_only_udm.principal.hostname, read_only_udm.principal.asset.hostname | Nilai kolom nama host |
log_time | read_only_udm.metadata.event_timestamp | Nilai kolom log_time dikonversi menjadi stempel waktu. Jika when dan device_time kosong, maka akan dipetakan ke read_only_udm.metadata.event_timestamp |
msg_desc | read_only_udm.metadata.description | Nilai kolom msg_desc |
os_details | read_only_udm.target.asset.platform_software.platform, read_only_udm.target.asset.platform_software.platform_version | Nilai kolom os_details. Jika os_details tidak kosong, maka os_details akan diuraikan untuk mengekstrak os_name dan os_ver. Jika os_name berisi Windows , maka read_only_udm.target.asset.platform_software.platform disetel ke WINDOWS . os_ver dipetakan ke read_only_udm.target.asset.platform_software.platform_version |
product_data.cs(Referer) | read_only_udm.network.http.referral_url | Nilai kolom product_data.cs(Referer) |
product_data.r-supplier-country | read_only_udm.principal.location.country_or_region | Nilai kolom product_data.r-supplier-country |
product_data.s-supplier-ip | read_only_udm.intermediary.ip, read_only_udm.intermediary.asset.ip | Nilai kolom product_data.s-supplier-ip |
product_data.x-bluecoat-application-name | read_only_udm.target.application | Nilai kolom product_data.x-bluecoat-application-name |
product_data.x-bluecoat-transaction-uuid | read_only_udm.metadata.product_log_id | Nilai kolom product_data.x-bluecoat-transaction-uuid |
product_data.x-client-agent-sw | read_only_udm.observer.platform_version | Nilai kolom product_data.x-client-agent-sw |
product_data.x-client-agent-type | read_only_udm.observer.application | Nilai kolom product_data.x-client-agent-type |
product_data.x-client-device-id | read_only_udm.target.resource.type, read_only_udm.target.resource.id, read_only_udm.target.resource.product_object_id | Jika tidak kosong, read_only_udm.target.resource.type disetel ke DEVICE . Nilai kolom product_data.x-client-device-id dipetakan ke read_only_udm.target.resource.id dan read_only_udm.target.resource.product_object_id |
product_data.x-client-device-name | read_only_udm.src.hostname, read_only_udm.src.asset.hostname | Nilai kolom product_data.x-client-device-name |
product_data.x-cs-client-ip-country | read_only_udm.target.location.country_or_region | Nilai kolom product_data.x-cs-client-ip-country |
product_data.x-cs-connection-negotiated-cipher | read_only_udm.network.tls.cipher | Nilai kolom product_data.x-cs-connection-negotiated-cipher |
product_data.x-cs-connection-negotiated-ssl-version | read_only_udm.network.tls.version_protocol | Nilai kolom product_data.x-cs-connection-negotiated-ssl-version |
product_data.x-exception-id | read_only_udm.security_result.summary | Nilai kolom product_data.x-exception-id |
product_data.x-rs-certificate-hostname | read_only_udm.network.tls.client.server_name | Nilai kolom product_data.x-rs-certificate-hostname |
product_data.x-rs-certificate-hostname-categories | read_only_udm.security_result.category_details | Nilai kolom product_data.x-rs-certificate-hostname-categories |
product_data.x-rs-certificate-observed-errors | read_only_udm.network.tls.server.certificate.issuer | Nilai kolom product_data.x-rs-certificate-observed-errors |
product_data.x-rs-certificate-validate-status | read_only_udm.network.tls.server.certificate.subject | Nilai kolom product_data.x-rs-certificate-validate-status |
product_name | read_only_udm.metadata.product_name | Nilai kolom product_name |
product_ver | read_only_udm.metadata.product_version | Nilai kolom product_ver |
proxy_connection.src_ip | read_only_udm.intermediary.ip, read_only_udm.intermediary.asset.ip | Nilai kolom proxy_connection.src_ip |
received_bytes | read_only_udm.network.received_bytes | Nilai kolom received_bytes dikonversi menjadi bilangan bulat |
ref_uid | read_only_udm.metadata.product_log_id | Nilai kolom ref_uid |
s_action | read_only_udm.metadata.description | Nilai kolom s_action |
sent_bytes | read_only_udm.network.sent_bytes | Nilai kolom sent_bytes dikonversi menjadi bilangan bulat |
severity_id | read_only_udm.security_result.severity | Jika severity_id adalah 1 atau 2, maka read_only_udm.security_result.severity disetel ke LOW . Jika severity_id adalah 3 atau 4, maka read_only_udm.security_result.severity disetel ke MEDIUM . Jika severity_id adalah 5 atau 6, maka read_only_udm.security_result.severity akan ditetapkan ke HIGH |
supplier_country | read_only_udm.principal.location.country_or_region | Nilai kolom supplier_country |
target_ip | read_only_udm.target.ip, read_only_udm.target.asset.ip | Nilai kolom target_ip |
user.full_name | read_only_udm.principal.user.user_display_name | Nilai kolom user.full_name |
user.name | read_only_udm.principal.user.user_display_name | Nilai kolom user.name |
user_name | read_only_udm.principal.user.user_display_name | Nilai kolom user_name |
uuid | read_only_udm.metadata.product_log_id | Nilai kolom uuid |
kapan | read_only_udm.metadata.event_timestamp | Nilai kolom when dikonversi menjadi stempel waktu |
read_only_udm.metadata.event_type | Disetel ke NETWORK_UNCATEGORIZED jika hostname kosong dan connection.dst_ip tidak kosong. Tetapkan ke SCAN_NETWORK jika nama host tidak kosong. Tetapkan ke NETWORK_CONNECTION jika has_principal dan has_target adalah true . Tetapkan ke STATUS_UPDATE jika has_principal adalah true dan has_target adalah false . Tetapkan ke GENERIC_EVENT jika has_principal dan has_target adalah false |
|
read_only_udm.metadata.log_type | Selalu ditetapkan ke SYMANTEC_WSS |
|
read_only_udm.metadata.vendor_name | Selalu ditetapkan ke SYMANTEC |
|
read_only_udm.security_result.action | Tetapkan ke ALLOW jika product_data.sc-filter_result adalah OBSERVED atau PROXIED . Tetapkan ke BLOCK jika product_data.sc-filter_result adalah DENIED |
|
read_only_udm.security_result.action_details | Nilai kolom product_data.sc-filter_result | |
read_only_udm.target.resource.type | Tetapkan ke DEVICE jika product_data.x-client-device-id tidak kosong |
Perlu bantuan lain? Dapatkan jawaban dari anggota Komunitas dan profesional Google SecOps.