Riferimento per parser

Importante

Lakewatch è in anteprima privata. Per richiedere l'accesso, contatta il team del tuo account Azure Databricks.

Un parser è un documento YAML che descrive le colonne di output di una sorgente di log di sicurezza. Un parser viene versionato e memorizzato in un catalogo e schema del Catalogo Unity; modificare un parser aggiunge una nuova versione immutabile, così che una sorgente di dati che pina una versione non è influenzata dalle modifiche successive. Questa pagina descrive la sintassi del parser che Lakewatch accetta.

Struttura del documento

description: Product audit events # what this log source is
fields:
  - name: event_name
    type: STRING
    required: true
    validate:
      in: ['sale', 'buy']
  - name: source_ip
    type: STRING
    observables: [ip]
  - name: actor
    type: VARIANT
    fields:
      - name: id
        type: STRING
        observables: [actor_id]
time:
  coalesce:
    - path: published
      time_formats: ['#rfc3339']

Puoi fornire description nel YAML come mostrato qui, oppure impostarlo nell'interfaccia utente quando crei il parser (consigliato).

Ora dell'evento

Ogni parser produce una time colonna: il timestamp dell'evento su cui Lakewatch si concentra. Devi definirlo con un blocco di time livello superiore invece che con un campo in fields; un parser personalizzato senza uno viene rifiutato. Poiché Lakewatch produce sempre la time colonna ed è sempre un TIMESTAMP, non imposti il suo name, type, o required. Non aggiungere un time campo a fields: il nome è riservato alla colonna che il blocco di time livello superiore produce, e un parser che lo dichiara come campo viene rifiutato.

Il blocco di livello superiore time prende una coalesce lista: una lista prioritaria di fonti che Lakewatch valuta in ordine, utilizzando il primo valore non nullo. Se ogni sorgente è nulla, Lakewatch torna al tempo di ingestione e imposta lw_meta.missing_timestamp a true. Ogni fonte è una delle seguenti:

  • Path: leggi il valore da una posizione di origine:

    time:
      coalesce:
        - path: published
          time_formats: ['#rfc3339']
    
  • Percorso con espressione regolare: estrarre il valore da una posizione sorgente con un regex:

    time:
      coalesce:
        - path: raw_message
          regexp: '<pattern>'
          match_group_index: 1 # which capture group holds the value; defaults to 1
          time_formats: ['#unix']
    

time_formats utilizza gli stessi set di formato e pattern di un TIMESTAMP campo. Vedi Timestamps.

Poiché time non è un campo, non viene usato nella classificazione. Per richiedere che il campo di tempo di evento di origine sia presente affinché un evento corrisponda, aggiungilo come required campo in fields.

Attributi di campo

Attribute Si applica a Description
name Tutti i campi Nome della colonna di uscita. Anche la chiave sorgente predefinita, a meno che path non sia impostata.
type Tutti i campi Tipo di colonna di uscita. Vedi Tipi supportati.
required Tutti i campi Se true, il campo deve essere presente affinché un evento corrisponda a questo parser. Di default è false.
path Tutti i campi Posizione della sorgente da cui leggere il valore, quando differisce da name, come published o actor.id.
comment Tutti i campi Descrizione del campo, emersa per aiutarti a scrivere regole di rilevamento.
time_formats TIMESTAMP tipi Elenco dei formati con cui analizzare il timestamp. Vedi Timestamps.
validate STRING Un singolo validatore. Vedi Validatori.
observables STRING Uno o più tipi osservabili da estrarre. Vedi Osservabili.
scan_for_observables VARIANT Regole di abbinamento delle chiavi per estrarre osservabili da contenuti annidati. Vedi Scansione per osservabili.
fields VARIANT Definizioni di campi annidati.
element ARRAY La definizione elementale dell'array.

Tipi supportati

STRING, BOOLEAN, TINYINT (BYTE), SMALLINT (SHORT), INT (INTEGER), BIGINT (LONG), FLOAT ,REALDECIMAL(p,s)DOUBLE , TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZBINARYVARIANTDATE, STRUCTe .ARRAY

Sono supportati solo i tipi sopra elencati. Per modellare oggetti annidati, usare VARIANT con l'interno fields. A VARIANT tollera campi aggiuntivi non definiti senza rompere il parser.

Scegliere tra STRUCT e VARIANT

STRUCT e VARIANT entrambi modellano dati annidati, ma fanno compromessi opposti. A STRUCT dichiara la forma subito: elenchi i suoi membri e i loro tipi, e la colonna analizzata contiene esattamente ciò che dichiari. A VARIANT mantiene il valore grezzo, semi-strutturato, intero, e lo leggi per percorso al momento della query, ad esempio con try_variant_get. Puoi comunque dichiarare fields sotto un VARIANT, ma questo attribuisce solo validazione e osservabili a quei percorsi; non perde il resto del valore.

Usalo STRUCT quando conosci la forma e vuoi un contratto stabile e dattiloscritto:

  • La forma rimane nella specifica del parser, quindi viene versionata e revisionata. Query, rilevamenti e dashboard leggono ogni membro come un tipo noto e non si interrompono quando i dati sorgente si spostano.
  • Le letture costano meno. A STRUCT è una vera colonna tipizzata a cui accedi con la notazione dei punti e che Spark può potare, mentre a VARIANT viene decodificata ad ogni lettura.
  • Il costo è la rigidità: tutto ciò che non dichiari viene eliminato, e devi aggiornare il parser quando la forma cambia.

Da usare VARIANT quando la forma è sconosciuta, in evoluzione o troppo grande per modellare campo per campo:

  • Si tiene aggiornato da sola sui cambiamenti dello schema. Fonti come AWS CloudTrail e Okta aggiungono campi senza alcun cambiamento nel parser.
  • Gestisce forme miste o in conflitto, come un percorso che è un oggetto in un evento e una stringa in un altro, che un singolo STRUCT tipo non può rappresentare.
  • Conserva il payload originale per un riprocessamento successivo e ti permette di atterrare prima i dati e modellarli dopo.
  • Scala su payload con centinaia di campi senza dichiarare ciascuno di essi.
  • Il costo è che non ottieni alcuna tipizzazione o validazione all'ingest, e paghi per estrarre i campi di ogni query. Un modello comune è promuovere i pochi campi che si interrogano di più in campi tipizzati.

Timestamp

Un TIMESTAMP campo viene analizzato con i formati elencati in time_formats, provati in ordine, usando parse_timestamp. Ogni voce è o una parola chiave predefinita nel formato o un vero e proprio schema di data-time di Spark:

Ingresso Meaning
#rfc3339 La famiglia RFC 3339.
#iso8601, #common, #extended Altre parole chiave predefinite nel formato.
#unix Un timestamp numerico Unix, in pochi secondi. I valori dei millisecondi non vengono rilevati.
MM/dd/yyyy hh:mm:ss a Un vero e proprio schema.

Elenca i formati che il log utilizza effettivamente in modo che l'analisi non sia eccessivamente permissiva.

Validatori

Un validatore afferma una condizione su un STRING campo. Usa esattamente uno dei seguenti metodi:

Validatore Vero quando
in: [...] Il valore è una delle stringhe elencate.
not_in: [...] Il valore non è una delle stringhe elencate.
contains_any: [...] Il valore contiene almeno una sottostringa elencata.
contains_none: [...] Il valore non contiene nessuna delle sottostringhe elencate.

Oggetti osservabili

Marcare un campo con observables estrae il suo valore nella colonna condivisa lw_observables per la caccia alla minaccia. Ogni tipo osservabile cattura un tipo specifico di valore e popola uno o più campi in lw_observables:

Osservabile Cattura Popola in lw_observables
ip Indirizzi IPv4 o IPv6 ip_addresses
domain Nomi di dominio hostnames
hostname Nomi host o indirizzi IP quando il valore è un IP hostnames, ip_addresses
url L'host di un URL (un nome host o IP) hostnames, ip_addresses
hash Hash MD5, SHA-1 e SHA-256 hashes
aws_arn Un ARN AWS, più l'ID account, l'ID dell'istanza, l'email e il nome utente che contiene account_ids, resource_ids, emails, usernames, device_ids
aws_account_id Un ID account AWS a 12 cifre account_ids
aws_instance_id Un ID di istanza EC2 device_ids
trace_id Un ID di richiesta o traccia request_trace_ids
username Un nome utente usernames
email Un indirizzo email e la parte con il nome utente emails, usernames
net_addr L'host di un host:port valore (un nome host o IP) hostnames, ip_addresses
mac Un indirizzo MAC mac_addresses
actor_id Un ID attore actor_ids
serial_number Un numero di serie serial_numbers
cve Un identificatore CVE, come CVE-2024-1234 cves
resource_tag Un tag risorsa resource_tags
mitre_attack_technique Un ID tecnico MITRE ATT&CK, come T1078 mitre_attack_technique_ids

lw_observables è una colonna gestita STRUCT da Lakewatch aggiunta a ogni tabella analizzata, con un ARRAY<STRING> campo per ogni tipo osservabile. Lakewatch normalizza, deduplica e ordina i valori di ogni campo e salta quelli invalidi; un campo senza valori è []. La colonna è presente in ogni evento, anche quando il parser dichiara che non è osservabile.

Scansione per osservabili

Usa l'attributo opzionale scan_for_observables su un VARIANT campo per estrarre osservabili da chiavi ovunque nel valore annidato, incluso il contenuto non dichiarato in fields. L'attributo non è valido per altri tipi di campo.

Mappare ogni tipo di osservabile che vuoi estrarre a un oggetto matcher esplicito. Un matcher può usare equals, ends_with, e contains; ogni chiave accetta un array di stringhe di nomi chiavi. L'abbinamento delle chiavi è indistinto per le maiuscole e minuscole (case by).

- name: request
  type: VARIANT
  scan_for_observables:
    ip:
      equals: [sourceIp, destinationIp]
      ends_with: [IpAddress]
      contains: [clientIp]
    email:
      equals: [principalEmail]
      ends_with: [Email]

Lakewatch esamina ricorsivamente le chiavi nel VARIANT valore. Quando una chiave corrisponde a una regola configurata, Lakewatch valida il valore candidato per quel tipo osservabile e aggiunge valori validi al campo corrispondente in lw_observables. L'abbinamento utilizza solo le regole nel parser; Lakewatch non aggiunge regole di abbinamento integrate.

Campi annidati e array

Usa VARIANT con fields per oggetti annidati e ARRAY con element per liste. Un elemento è definito come un campo, ma senza name, required, o path:

- name: resources
  type: ARRAY
  path: resources
  element:
    type: VARIANT
    fields:
      - name: accountId
        type: STRING
        observables: [aws_account_id]
- name: source_ips
  type: ARRAY
  path: sourceIps
  element:
    type: STRING
    observables: [ip]

Classification

Una sorgente dati può avere diversi parser collegati. Ogni evento in arrivo viene abbinato agli analisi nell'ordine in cui viene dichiarato e si piazza nel primo parser che corrisponde. Un evento corrisponde quando sono presenti i campi richiesti, i suoi campi tipizzati si convertono nei tipi dichiarati e tutti i validatori passano il testo. Gli eventi non abbinati vengono instradati a un sentinel dead-letter invece di fallire la pipeline.

Parser integrati e personalizzati

Lakewatch fornisce parser integrati per le fonti comuni dei log di sicurezza e ti permette di creare parser personalizzati per fonti non coperte o che vuoi personalizzare. Entrambi utilizzano il formato YAML descritto sopra.

Scopri e ispeziona i parser integrati

Quando associ i parser a una sorgente dati, puoi consultare i parser integrati disponibili e selezionare quelli che corrispondono alla tua fonte. Ispeziona un parser integrato per vedere le colonne che produce (campi, tipi, validatori e osservabili) prima di allegarlo, così potrai confermare che corrisponde agli eventi che stai assumendo.

Gli parser integrati sono di sola lettura. Per personalizzarne uno, usa l'azione Clone sul parser per creare un parser personalizzato modificabile basato sulla definizione integrata del parser, poi aggiustalo e salva. Il clonaggio è una comodità dell'interfaccia utente che copia la definizione in un nuovo parser personalizzato (versione 1). Non è un'operazione clone lato server, e il parser integrato è rimasto invariato.

Autore di un parser personalizzato

Per creare un parser personalizzato, fornisci un documento YAML nel formato descritto sopra e salvalo in un catalogo e schema del Catalogo Unity. Creare un parser memorizza la definizione come versione 1 e ti registra come proprietario del parser.

Definisci attentamente i tuoi campi, perché un evento che non corrisponde a nessun parser viene instradato a un sentinel dead-letter invece di fallire la pipeline. Un evento i cui valori non si convertono nei tipi dichiarati, o che fallisce un validatore, non corrisponderà al parser.

Versioning e cancellazione

Modificare un parser aggiunge una nuova versione immutabile. Le versioni esistenti non vengono mai modificate e i numeri di versione non vengono mai riutilizzati. Il server assegna a ogni nuova versione il numero successivo in sequenza. Solo il proprietario del parser può aggiungere una versione.

Una sorgente di dati fissa una versione specifica, quindi continua a usarla finché non la cambi esplicitamente. Vedi Modifica la versione di un parser.

Puoi eliminare un intero parser personalizzato, rimuovendo così tutte le sue versioni. Non esiste un'operazione per eliminare una singola versione. Solo il proprietario può eliminare un parser, e la cancellazione viene bloccata mentre qualsiasi fonte dati fa riferimento a qualsiasi versione del parser. Prima di eliminare, stacca il parser da ogni fonte dati che lo utilizza (cambia ogni fonte con un parser diverso e salva la modifica) poi elimina il parser.

Limits

Un documento parser ha al massimo 256 KB.