Raccogliere i log di Symantec WSS

Supportato in:

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)

  1. Accedi al portale Symantec Web Security Service come amministratore.
  2. Vai ad Account > Credenziali API.
  3. Fai clic su Aggiungi.
  4. 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.
  5. Fai clic su Salva e copia in modo sicuro le credenziali API generate.
  6. Registra l'URL del portale WSS e l'endpoint dell'API Sync.
  7. 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

  1. Crea un bucket Amazon S3 seguendo questa guida utente: Creazione di un bucket
  2. Salva il nome e la regione del bucket per riferimento futuro (ad esempio, symantec-wss-logs).
  3. Crea un utente seguendo questa guida utente: Creazione di un utente IAM.
  4. Seleziona l'utente creato.
  5. Seleziona la scheda Credenziali di sicurezza.
  6. Fai clic su Crea chiave di accesso nella sezione Chiavi di accesso.
  7. Seleziona Servizio di terze parti come Caso d'uso.
  8. Fai clic su Avanti.
  9. (Facoltativo) Aggiungi un tag di descrizione.
  10. Fai clic su Crea chiave di accesso.
  11. Fai clic su Scarica file CSV per salvare la chiave di accesso e la chiave di accesso segreta per riferimento futuro.
  12. Fai clic su Fine.
  13. Seleziona la scheda Autorizzazioni.
  14. Fai clic su Aggiungi autorizzazioni nella sezione Criteri per le autorizzazioni.
  15. Seleziona Aggiungi autorizzazioni.
  16. Seleziona Allega direttamente i criteri.
  17. Cerca i criteri AmazonS3FullAccess.
  18. Seleziona la policy.
  19. Fai clic su Avanti.
  20. Fai clic su Aggiungi autorizzazioni.

Configura il ruolo e il criterio IAM per i caricamenti S3

  1. Nella console AWS, vai a IAM > Policy.
  2. Fai clic su Crea criterio > scheda JSON.
  3. Copia e incolla i seguenti criteri.
  4. 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"
        }
      ]
    }
    
  5. Fai clic su Avanti > Crea criterio.

  6. Vai a IAM > Ruoli > Crea ruolo > Servizio AWS > Lambda.

  7. Allega il criterio appena creato.

  8. Assegna al ruolo il nome SymantecWssToS3Role e fai clic su Crea ruolo.

Crea la funzione Lambda

  1. Nella console AWS, vai a Lambda > Funzioni > Crea funzione.
  2. Fai clic su Crea autore da zero.
  3. 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
  4. 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())
    
  5. Vai a Configurazione > Variabili di ambiente.

  6. Fai clic su Modifica > Aggiungi nuova variabile di ambiente.

  7. 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
  8. Dopo aver creato la funzione, rimani sulla relativa pagina (o apri Lambda > Funzioni > la tua funzione).

  9. Seleziona la scheda Configurazione.

  10. Nel riquadro Configurazione generale, fai clic su Modifica.

  11. Modifica Timeout impostando 5 minuti (300 secondi) e fai clic su Salva.

Creare una pianificazione EventBridge

  1. Vai a Amazon EventBridge > Scheduler > Crea pianificazione.
  2. Fornisci i seguenti dettagli di configurazione:
    • Programma ricorrente: Tariffa (1 hour).
    • Target: la tua funzione Lambda symantec_wss_to_s3.
    • Nome: symantec-wss-1h
  3. Fai clic su Crea pianificazione.

(Facoltativo) Crea chiavi e utenti IAM di sola lettura per Google SecOps

  1. Nella console AWS, vai a IAM > Utenti.
  2. Fai clic su Add users (Aggiungi utenti).
  3. Fornisci i seguenti dettagli di configurazione:
    • Utente: inserisci secops-reader.
    • Tipo di accesso: seleziona Chiave di accesso - Accesso programmatico.
  4. Fai clic su Crea utente.
  5. Collega la criterio per la lettura minima (personalizzata): Utenti > secops-reader > Autorizzazioni > Aggiungi autorizzazioni > Collega le norme direttamente > Crea norma.
  6. 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"
        }
      ]
    }
    
  7. Name = secops-reader-policy.

  8. Fai clic su Crea criterio > cerca/seleziona > Avanti > Aggiungi autorizzazioni.

  9. Crea la chiave di accesso per secops-reader: Credenziali di sicurezza > Chiavi di accesso.

  10. Fai clic su Crea chiave di accesso.

  11. Scarica il file CSV. Incollerai questi valori nel feed.

Configura un feed in Google SecOps per importare i log di Symantec WSS

  1. Vai a Impostazioni SIEM > Feed.
  2. Fai clic su + Aggiungi nuovo feed.
  3. Nel campo Nome feed, inserisci un nome per il feed (ad esempio, Symantec WSS logs).
  4. Seleziona Amazon S3 V2 come Tipo di origine.
  5. Seleziona Symantec WSS come tipo di log.
  6. Fai clic su Avanti.
  7. 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.
  8. Fai clic su Avanti.
  9. 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.