Raccogliere i log di Symantec WSS
Questo documento spiega come importare i log di Symantec Web Security Service (WSS) in Google Security Operations utilizzando Amazon S3. Il parser tenta innanzitutto di analizzare il messaggio di log come JSON. Se l'operazione non va a buon fine, utilizza una serie di pattern grok sempre più specifici per estrarre i campi dal testo non elaborato, mappando infine i dati estratti al modello Unified Data Model (UDM).
Prima di iniziare
Assicurati di soddisfare i seguenti prerequisiti:
- Un'istanza Google SecOps.
- Accesso con privilegi a Symantec Web Security Service.
- Accesso privilegiato ad AWS (S3, Identity and Access Management (IAM), Lambda, EventBridge).
Raccogli i prerequisiti di Symantec WSS (ID, chiavi API, ID organizzazione, token)
- Accedi al portale Symantec Web Security Service come amministratore.
- Vai ad Account > Credenziali API.
- Fai clic su Aggiungi.
- Fornisci i seguenti dettagli di configurazione:
- Nome API: inserisci un nome descrittivo (ad esempio,
Google SecOps Integration
). - Descrizione: inserisci una descrizione per le credenziali API.
- Nome API: inserisci un nome descrittivo (ad esempio,
- Fai clic su Salva e copia in modo sicuro le credenziali API generate.
- Registra l'URL del portale WSS e l'endpoint dell'API Sync.
- Copia e salva in una posizione sicura i seguenti dettagli:
- WSS_API_USERNAME.
- WSS_API_PASSWORD.
- WSS_SYNC_URL.
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,
symantec-wss-logs
). - Crea un utente seguendo questa guida utente: 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 riferimento futuro.
- 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 i criteri AmazonS3FullAccess.
- Seleziona la policy.
- Fai clic su Avanti.
- Fai clic su Aggiungi autorizzazioni.
Configura il ruolo e il criterio IAM per i caricamenti S3
- Nella console AWS, vai a IAM > Policy.
- Fai clic su Crea criterio > scheda JSON.
- Copia e incolla i seguenti criteri.
JSON delle policy (sostituisci
symantec-wss-logs
se hai inserito un nome del bucket diverso):{ "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" } ] }
Fai clic su Avanti > Crea criterio.
Vai a IAM > Ruoli > Crea ruolo > Servizio AWS > Lambda.
Allega il criterio appena creato.
Assegna al ruolo il nome
SymantecWssToS3Role
e fai clic su Crea ruolo.
Crea la funzione Lambda
- Nella console AWS, vai a Lambda > Funzioni > Crea funzione.
- Fai clic su Crea autore da zero.
Fornisci i seguenti dettagli di configurazione:
Impostazione Valore Nome symantec_wss_to_s3
Tempo di esecuzione Python 3.13 Architettura x86_64 Ruolo di esecuzione SymantecWssToS3Role
Dopo aver creato la funzione, apri la scheda Codice, elimina lo stub e incolla il seguente codice (
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())
Vai a Configurazione > Variabili di ambiente.
Fai clic su Modifica > Aggiungi nuova variabile di ambiente.
Inserisci le variabili di ambiente fornite nella tabella seguente, sostituendo i valori di esempio con i tuoi valori.
Variabili di ambiente
Chiave Valore di esempio 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
(dal passaggio 2)WSS_API_PASSWORD
your-api-password
(dal passaggio 2)WSS_TOKEN_PARAM
none
Dopo aver creato la funzione, rimani sulla relativa pagina (o apri Lambda > Funzioni > la tua funzione).
Seleziona la scheda Configurazione.
Nel riquadro Configurazione generale, fai clic su Modifica.
Modifica Timeout impostando 5 minuti (300 secondi) e fai clic su Salva.
Creare una pianificazione EventBridge
- Vai a Amazon EventBridge > Scheduler > Crea pianificazione.
- Fornisci i seguenti dettagli di configurazione:
- Programma ricorrente: Tariffa (
1 hour
). - Target: la tua funzione Lambda
symantec_wss_to_s3
. - Nome:
symantec-wss-1h
- Programma ricorrente: Tariffa (
- Fai clic su Crea pianificazione.
(Facoltativo) Crea chiavi e utenti IAM di sola lettura per Google SecOps
- Nella console AWS, vai a IAM > Utenti.
- Fai clic su Add users (Aggiungi utenti).
- Fornisci i seguenti dettagli di configurazione:
- Utente: inserisci
secops-reader
. - Tipo di accesso: seleziona Chiave di accesso - Accesso programmatico.
- Utente: inserisci
- Fai clic su Crea utente.
- Collega la criterio per la lettura minima (personalizzata): Utenti > secops-reader > Autorizzazioni > Aggiungi autorizzazioni > Collega le norme direttamente > Crea norma.
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" } ] }
Name =
secops-reader-policy
.Fai clic su Crea criterio > cerca/seleziona > Avanti > Aggiungi autorizzazioni.
Crea la chiave di accesso per
secops-reader
: Credenziali di sicurezza > Chiavi di accesso.Fai clic su Crea chiave di accesso.
Scarica il file CSV. Incollerai questi valori nel feed.
Configura un feed in Google SecOps per importare i log di Symantec WSS
- Vai a Impostazioni SIEM > Feed.
- Fai clic su + Aggiungi nuovo feed.
- Nel campo Nome feed, inserisci un nome per il feed (ad esempio,
Symantec WSS logs
). - Seleziona Amazon S3 V2 come Tipo di origine.
- Seleziona Symantec WSS come tipo di log.
- Fai clic su Avanti.
- Specifica i valori per i seguenti parametri di input:
- URI S3:
s3://symantec-wss-logs/symantec/wss/
- Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
- Età massima del file: includi i file modificati nell'ultimo numero di giorni. Il valore predefinito è 180 giorni.
- ID chiave di accesso: chiave di accesso utente con accesso al bucket S3.
- Chiave di accesso segreta: chiave segreta dell'utente con accesso al bucket S3.
- Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset.
- Etichette di importazione: l'etichetta applicata agli eventi di questo feed.
- 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 |
---|---|---|
category_id | read_only_udm.metadata.product_event_type | Se category_id è 1, read_only_udm.metadata.product_event_type è impostato su Security . Se category_id è 5, read_only_udm.metadata.product_event_type è impostato su Policy |
collector_device_ip | read_only_udm.principal.ip, read_only_udm.principal.asset.ip | Valore del campo collector_device_ip |
connection.bytes_download | read_only_udm.network.received_bytes | Valore del campo connection.bytes_download convertito in numero intero |
connection.bytes_upload | read_only_udm.network.sent_bytes | Valore del campo connection.bytes_upload convertito in numero intero |
connection.dst_ip | read_only_udm.target.ip | Valore del campo connection.dst_ip |
connection.dst_location.country | read_only_udm.target.location.country_or_region | Valore del campo connection.dst_location.country |
connection.dst_name | read_only_udm.target.hostname | Valore del campo connection.dst_name |
connection.dst_port | read_only_udm.target.port | Valore del campo connection.dst_port convertito in numero intero |
connection.http_status | read_only_udm.network.http.response_code | Valore del campo connection.http_status convertito in numero intero |
connection.http_user_agent | read_only_udm.network.http.user_agent | Valore del campo connection.http_user_agent |
connection.src_ip | read_only_udm.principal.ip, read_only_udm.src.ip | Valore del campo connection.src_ip. Se src_ip o collector_device_ip non è vuoto, viene mappato a read_only_udm.src.ip |
connection.tls.version | read_only_udm.network.tls.version_protocol | Valore del campo connection.tls.version |
connection.url.host | read_only_udm.target.hostname | Valore del campo connection.url.host |
connection.url.method | read_only_udm.network.http.method | Valore del campo connection.url.method |
connection.url.path | read_only_udm.target.url | Valore del campo connection.url.path |
connection.url.text | read_only_udm.target.url | Valore del campo connection.url.text |
cs_connection_negotiated_cipher | read_only_udm.network.tls.cipher | Valore del campo cs_connection_negotiated_cipher |
cs_icap_status | read_only_udm.security_result.description | Valore del campo cs_icap_status |
device_id | read_only_udm.target.resource.id, read_only_udm.target.resource.product_object_id | Valore del campo device_id |
device_ip | read_only_udm.intermediary.ip, read_only_udm.intermediary.asset.ip | Valore del campo device_ip |
device_time | read_only_udm.metadata.collected_timestamp, read_only_udm.metadata.event_timestamp | Valore del campo device_time convertito in stringa. Se when è vuoto, viene mappato a read_only_udm.metadata.event_timestamp |
nome host | read_only_udm.principal.hostname, read_only_udm.principal.asset.hostname | Valore del campo Nome host |
log_time | read_only_udm.metadata.event_timestamp | Valore del campo log_time convertito in timestamp. Se when e device_time sono vuoti, viene mappato a read_only_udm.metadata.event_timestamp |
msg_desc | read_only_udm.metadata.description | Valore del campo msg_desc |
os_details | read_only_udm.target.asset.platform_software.platform, read_only_udm.target.asset.platform_software.platform_version | Valore del campo os_details. Se os_details non è vuoto, viene analizzato per estrarre os_name e os_ver. Se os_name contiene Windows , read_only_udm.target.asset.platform_software.platform è impostato su WINDOWS . os_ver è mappato a read_only_udm.target.asset.platform_software.platform_version |
product_data.cs(Referer) | read_only_udm.network.http.referral_url | Valore del campo product_data.cs(Referer) |
product_data.r-supplier-country | read_only_udm.principal.location.country_or_region | Valore del campo product_data.r-supplier-country |
product_data.s-supplier-ip | read_only_udm.intermediary.ip, read_only_udm.intermediary.asset.ip | Valore del campo product_data.s-supplier-ip |
product_data.x-bluecoat-application-name | read_only_udm.target.application | Valore del campo product_data.x-bluecoat-application-name |
product_data.x-bluecoat-transaction-uuid | read_only_udm.metadata.product_log_id | Valore del campo product_data.x-bluecoat-transaction-uuid |
product_data.x-client-agent-sw | read_only_udm.observer.platform_version | Valore del campo product_data.x-client-agent-sw |
product_data.x-client-agent-type | read_only_udm.observer.application | Valore del campo 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 | Se non è vuoto, read_only_udm.target.resource.type è impostato su DEVICE . Il valore del campo product_data.x-client-device-id viene mappato a read_only_udm.target.resource.id e 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 | Valore del campo product_data.x-client-device-name |
product_data.x-cs-client-ip-country | read_only_udm.target.location.country_or_region | Valore del campo product_data.x-cs-client-ip-country |
product_data.x-cs-connection-negotiated-cipher | read_only_udm.network.tls.cipher | Valore del campo product_data.x-cs-connection-negotiated-cipher |
product_data.x-cs-connection-negotiated-ssl-version | read_only_udm.network.tls.version_protocol | Valore del campo product_data.x-cs-connection-negotiated-ssl-version |
product_data.x-exception-id | read_only_udm.security_result.summary | Valore del campo product_data.x-exception-id |
product_data.x-rs-certificate-hostname | read_only_udm.network.tls.client.server_name | Valore del campo product_data.x-rs-certificate-hostname |
product_data.x-rs-certificate-hostname-categories | read_only_udm.security_result.category_details | Valore del campo product_data.x-rs-certificate-hostname-categories |
product_data.x-rs-certificate-observed-errors | read_only_udm.network.tls.server.certificate.issuer | Valore del campo product_data.x-rs-certificate-observed-errors |
product_data.x-rs-certificate-validate-status | read_only_udm.network.tls.server.certificate.subject | Valore del campo product_data.x-rs-certificate-validate-status |
product_name | read_only_udm.metadata.product_name | Valore del campo product_name |
product_ver | read_only_udm.metadata.product_version | Valore del campo product_ver |
proxy_connection.src_ip | read_only_udm.intermediary.ip, read_only_udm.intermediary.asset.ip | Valore del campo proxy_connection.src_ip |
received_bytes | read_only_udm.network.received_bytes | Valore del campo received_bytes convertito in numero intero |
ref_uid | read_only_udm.metadata.product_log_id | Valore del campo ref_uid |
s_action | read_only_udm.metadata.description | Valore del campo s_action |
sent_bytes | read_only_udm.network.sent_bytes | Valore del campo sent_bytes convertito in numero intero |
severity_id | read_only_udm.security_result.severity | Se severity_id è 1 o 2, read_only_udm.security_result.severity è impostato su LOW . Se severity_id è 3 o 4, read_only_udm.security_result.severity è impostato su MEDIUM . Se severity_id è 5 o 6, read_only_udm.security_result.severity è impostato su HIGH |
supplier_country | read_only_udm.principal.location.country_or_region | Valore del campo supplier_country |
target_ip | read_only_udm.target.ip, read_only_udm.target.asset.ip | Valore del campo target_ip |
user.full_name | read_only_udm.principal.user.user_display_name | Valore del campo user.full_name |
nome.utente | read_only_udm.principal.user.user_display_name | Valore del campo user.name |
user_name | read_only_udm.principal.user.user_display_name | Valore del campo user_name |
uuid | read_only_udm.metadata.product_log_id | Valore del campo uuid |
quando | read_only_udm.metadata.event_timestamp | Valore del campo convertito in timestamp |
read_only_udm.metadata.event_type | Impostato su NETWORK_UNCATEGORIZED se il nome host è vuoto e connection.dst_ip non è vuoto. Impostato su SCAN_NETWORK se il nome host non è vuoto. Imposta su NETWORK_CONNECTION se has_principal e has_target sono true . Imposta su STATUS_UPDATE se has_principal è true e has_target è false . Impostato su GENERIC_EVENT se has_principal e has_target sono false |
|
read_only_udm.metadata.log_type | Sempre impostato su SYMANTEC_WSS |
|
read_only_udm.metadata.vendor_name | Sempre impostato su SYMANTEC |
|
read_only_udm.security_result.action | Imposta su ALLOW se product_data.sc-filter_result è OBSERVED o PROXIED . Imposta su BLOCK se product_data.sc-filter_result è DENIED |
|
read_only_udm.security_result.action_details | Valore del campo product_data.sc-filter_result | |
read_only_udm.target.resource.type | Imposta su DEVICE se product_data.x-client-device-id non è vuoto |
Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.