Aller au contenu principal

Référence de l’analyseur

info

Aperçu

Lakewatch est en aperçu privé. Pour demander l'accès, contactez l'équipe de votre compte Databricks.

Un analyseur est un document YAML qui décrit les colonnes de sortie d’une source de logs de sécurité. Un analyseur est versionné et stocké dans un catalogue et un schéma Unity Catalog ; la modification d’un analyseur ajoute une nouvelle version immuable, de sorte qu’une source de données qui pin une version n’est pas affectée par des modifications ultérieures. Cette page décrit la syntaxe de l'analyseur acceptée par Lakewatch.

Structure du document​

YAML
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']

Vous pouvez fournir description dans le YAML comme indiqué ici, ou le définir dans l’interface utilisateur lorsque vous créez l’analyseur (recommandé).

Heure de l'événement​

Chaque analyseur produit une colonne time : le timestamp de l’événement sur lequel Lakewatch clusters les données. Vous devez le définir avec un bloc time de haut niveau plutôt qu’avec un champ dans fields; un analyseur personnalisé sans bloc de ce type sera rejeté. Parce que Lakewatch produit toujours la colonne time et qu'il s'agit toujours d'un TIMESTAMP, vous ne définissez pas son name, type ou required. N’ajoutez pas de champ time à fields: le nom est réservé à la colonne produite par le bloc de haut niveau time, et un analyseur syntaxique qui le déclare comme un champ est rejeté.

Le bloc time de niveau supérieur prend une liste coalesce : une liste hiérarchisée de sources que Lakewatch évalue dans l'ordre, en utilisant la première valeur non nulle. Si chaque source est nulle, Lakewatch revient au temps d'ingestion et définit lw_meta.missing_timestamp sur true. Chaque source est l'une des suivantes :

  • Chemin : lire la valeur à partir d’un emplacement source :

    YAML
    time:
    coalesce:
    - path: published
    time_formats: ['#rfc3339']
  • Chemin avec une expression régulière : extrayez la valeur d’un emplacement source à l’aide d’une expression régulière :

    YAML
    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 utilise les mêmes ensembles de formats et modèles qu’un champ TIMESTAMP. Voir Timestamps.

Comme time n’est pas un champ, il n’est pas utilisé dans la classification. Pour exiger que le champ de l'heure de l'événement source soit présent pour qu'un événement corresponde, ajoutez-le en tant que champ required dans fields.

Attributs de champ​

Attribut

S’applique à

Description

name

Tous les champs

Nom de la colonne de sortie. Également la clé source default, sauf si path est défini.

type

Tous les champs

Type de colonne de sortie. Voir Types pris en charge.

required

Tous les champs

Si true est vrai, le champ doit être présent pour qu'un événement corresponde à cet analyseur. default sur false.

path

Tous les champs

Emplacement source à partir duquel lire la valeur lorsqu'il est différent de name, par exemple published ou actor.id.

comment

Tous les champs

Description du champ, affichée pour vous aider à rédiger des règles de détection.

time_formats

TIMESTAMP types

Liste des formats pour analyser le timestamp avec. Voir Timestamps.

validate

STRING

Un seul validateur. Voir Validateurs.

observables

STRING

Un ou plusieurs types d’observables à extraire. Voir Observables.

scan_for_observables

VARIANT

Règles de correspondance de clé pour extraire les observables du contenu imbriqué. Voir Rechercher des observables.

fields

VARIANT

Définitions de champs imbriqués.

element

ARRAY

La définition des éléments du tableau.

Attribut

S’applique à

Description

name

Tous les champs

Nom de la colonne de sortie. Également la clé source default, sauf si path est défini.

type

Tous les champs

Type de colonne de sortie. Voir Types pris en charge.

required

Tous les champs

Si true est vrai, le champ doit être présent pour qu'un événement corresponde à cet analyseur. default sur false.

path

Tous les champs

Emplacement source à partir duquel lire la valeur lorsqu'il est différent de name, par exemple published ou actor.id.

comment

Tous les champs

Description du champ, affichée pour vous aider à rédiger des règles de détection.

time_formats

TIMESTAMP types

Liste des formats pour analyser le timestamp avec. Voir Timestamps.

validate

STRING

Un seul validateur. Voir Validateurs.

observables

STRING

Un ou plusieurs types d’observables à extraire. Voir Observables.

scan_for_observables

VARIANT

Règles de correspondance de clé pour extraire les observables du contenu imbriqué. Voir Rechercher des observables.

fields

VARIANT

Définitions de champs imbriqués.

element

ARRAY

La définition des éléments du tableau.

Types pris en charge​

STRING, BOOLEAN, TINYINT (BYTE), SMALLINT (SHORT), INT (INTEGER), BIGINT (LONG), FLOAT (REAL), DOUBLE, DECIMAL(p,s), TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZ, DATE, BINARY, VARIANT, STRUCT, et ARRAY.

Seuls les types répertoriés ci-dessus sont pris en charge. Pour modéliser des objets imbriqués, utilisez VARIANT avec fields en interne. Un VARIANT tolère des champs supplémentaires non déclarés sans interrompre l’analyseur.

Choisir entre STRUCT et VARIANT​

STRUCT et VARIANT modélisent des données imbriquées, mais font des compromis opposés. Un STRUCT déclare la forme à l’avance : vous listez ses membres et leurs types, et la colonne analysée contient exactement ce que vous déclarez. Un VARIANT conserve la valeur brute et semi-structurée intacte, et vous la lisez par chemin au moment de la query, par exemple avec try_variant_get. Vous pouvez toujours déclarer fields sous VARIANT, mais cela ne fait qu’attacher la validation et les observables à ces chemins ; cela ne supprime pas le reste de la valeur.

Utilisez STRUCT lorsque vous connaissez la forme et que vous souhaitez un contrat stable et typé :

  • La forme réside dans la spécification du parser, elle est donc versionnée et révisée. Les requêtes, les détections et les tableaux de bord lisent chaque membre comme un type connu et ne sont pas interrompus lorsque les données sources changent.
  • Les lectures sont moins coûteuses. Un STRUCT est une colonne typée réelle à laquelle vous accédez avec la notation par point et que Spark peut élaguer, alors qu’un VARIANT est décodé à chaque lecture.
  • Le coût est la rigidité : tout ce que vous ne déclarez pas est abandonné, et vous devez mettre à jour le parser lorsque la forme change.

Utilisez VARIANT lorsque la forme est inconnue, en évolution ou trop volumineuse pour modéliser champ par champ :

  • Il se maintient avec les changements de schéma de son propre chef. Des sources telles qu’AWS CloudTrail et Okta ajoutent des champs sans changement de l’analyseur.
  • Il gère des formes mixtes ou contradictoires, comme un chemin qui est un objet dans un événement et une chaîne dans un autre, qu'un seul type STRUCT ne peut pas représenter.
  • Elle préserve la charge utile d'origine en vue d'un traitement ultérieur et permet de déposer les données d'abord et de les modéliser ensuite.
  • Il monte en charge pour les charges utiles avec des centaines de champs sans qu'il soit nécessaire de déclarer chacun d'eux.
  • Le coût est que vous n'obtenez aucun typage ou validation lors de l'ingestion, et que vous payez pour extraire des champs à chaque query. Un modèle courant consiste à promouvoir les quelques champs que vous query le plus en champs typés.

Timestamps​

Un champ TIMESTAMP est analysé selon les formats listés dans time_formats, essayés dans l'ordre, en utilisant parse_timestamp. Chaque entrée est soit un mot-clé de format prédéfini, soit un modèle de date/heure littéral de Spark :

Entrée

Signification

#rfc3339

La famille RFC 3339.

#iso8601, #common, #extended

Autres mots-clés de format prédéfinis.

#unix

Timestamp Unix numérique, en secondes. Les valeurs en millisecondes ne sont pas détectées.

MM/dd/yyyy hh:mm:ss a

Modèle littéral.

Entrée

Signification

#rfc3339

La famille RFC 3339.

#iso8601, #common, #extended

Autres mots-clés de format prédéfinis.

#unix

Timestamp Unix numérique, en secondes. Les valeurs en millisecondes ne sont pas détectées.

MM/dd/yyyy hh:mm:ss a

Modèle littéral.

Listez les formats réellement utilisés par les Logs afin que l'analyse ne soit pas trop permissive.

Validateurs​

Un validateur impose une condition sur un champ STRING. Utilisez exactement une des options suivantes :

Validateur

Vrai si

in: [...]

La valeur est l'une des chaînes de caractères listées.

not_in: [...]

La valeur ne fait pas partie des chaînes répertoriées.

contains_any: [...]

La valeur contient au moins une sous-chaîne répertoriée.

contains_none: [...]

La valeur ne contient aucune des sous-chaînes répertoriées.

Validateur

Vrai si

in: [...]

La valeur est l'une des chaînes de caractères listées.

not_in: [...]

La valeur ne fait pas partie des chaînes répertoriées.

contains_any: [...]

La valeur contient au moins une sous-chaîne répertoriée.

contains_none: [...]

La valeur ne contient aucune des sous-chaînes répertoriées.

Observables​

Marquer un champ avec observables extrait sa valeur dans la colonne partagée lw_observables pour la recherche de menaces. Chaque type d’observable capture un type spécifique de valeur et remplit un ou plusieurs champs dans lw_observables:

Observable

Captures

Peuple dans lw_observables

ip

Adresses IPv4 ou IPv6

ip_addresses

domain

Noms de domaine

hostnames

hostname

Hostname ou adresses IP lorsque la valeur est une IP

hostnames, ip_addresses

url

L'hôte d'une URL (un hostname ou une IP)

hostnames, ip_addresses

hash

Hachages MD5, SHA-1 et SHA-256

hashes

aws_arn

Un ARN AWS, ainsi que l’identifiant du compte, l’identifiant de l’instance, l’e-mail et le nom d’utilisateur qu’il contient

account_ids, resource_ids, emails, usernames, device_ids

aws_account_id

ID de compte AWS à 12 chiffres

account_ids

aws_instance_id

ID d'instance EC2

device_ids

trace_id

Identifiant de requête ou de trace

request_trace_ids

username

Un nom d'utilisateur

usernames

email

Une adresse e-mail et sa partie nom d'utilisateur

emails, usernames

net_addr

L'hôte d'une valeur host:port (Hostname ou IP)

hostnames, ip_addresses

mac

Une adresse MAC

mac_addresses

actor_id

ID d'acteur

actor_ids

serial_number

Numéro de série

serial_numbers

cve

Un identifiant CVE, comme CVE-2024-1234

cves

resource_tag

Tag de ressource

resource_tags

mitre_attack_technique

Un ID de technique MITRE ATT&CK, tel que T1078

mitre_attack_technique_ids

Observable

Captures

Peuple dans lw_observables

ip

Adresses IPv4 ou IPv6

ip_addresses

domain

Noms de domaine

hostnames

hostname

Hostname ou adresses IP lorsque la valeur est une IP

hostnames, ip_addresses

url

L'hôte d'une URL (un hostname ou une IP)

hostnames, ip_addresses

hash

Hachages MD5, SHA-1 et SHA-256

hashes

aws_arn

Un ARN AWS, ainsi que l’identifiant du compte, l’identifiant de l’instance, l’e-mail et le nom d’utilisateur qu’il contient

account_ids, resource_ids, emails, usernames, device_ids

aws_account_id

ID de compte AWS à 12 chiffres

account_ids

aws_instance_id

ID d'instance EC2

device_ids

trace_id

Identifiant de requête ou de trace

request_trace_ids

username

Un nom d'utilisateur

usernames

email

Une adresse e-mail et sa partie nom d'utilisateur

emails, usernames

net_addr

L'hôte d'une valeur host:port (Hostname ou IP)

hostnames, ip_addresses

mac

Une adresse MAC

mac_addresses

actor_id

ID d'acteur

actor_ids

serial_number

Numéro de série

serial_numbers

cve

Un identifiant CVE, comme CVE-2024-1234

cves

resource_tag

Tag de ressource

resource_tags

mitre_attack_technique

Un ID de technique MITRE ATT&CK, tel que T1078

mitre_attack_technique_ids

lw_observables est une colonne STRUCT gérée par Lakewatch ajoutée à chaque table analysée, avec un champ ARRAY<STRING> par type observable. Lakewatch normalise, déduplique et trie les valeurs de chaque champ et ignore les valeurs non valides ; un champ sans valeur est []. La colonne est présente sur chaque événement, même lorsque le parseur ne déclare aucune observable.

Scanner les observables​

Utilisez l’attribut facultatif scan_for_observables sur un champ VARIANT pour extraire des observables à partir de clés situées n’importe où dans la valeur imbriquée, y compris le contenu non déclaré dans fields. L'attribut n'est pas valide sur d'autres types de champs.

Mappez chaque type d'observable que vous souhaitez extraire vers un objet de correspondance explicite. Un moteur de correspondance peut utiliser equals, ends_with et contains; chaque clé accepte un tableau de chaînes de noms de clé. La correspondance des clés ne fait pas la distinction entre les majuscules et les minuscules.

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

Lakewatch examine récursivement les clés dans la valeur VARIANT. Lorsqu’une clé correspond à une règle configurée, Lakewatch valide la valeur candidate pour ce type observable et ajoute des valeurs valides au champ correspondant dans lw_observables. La correspondance utilise uniquement les règles de l'analyseur ; Lakewatch n'ajoute pas de règles de correspondance intégrées.

Champs imbriqués et en tableau​

Utilisez VARIANT avec fields pour les objets imbriqués, et ARRAY avec element pour les listes. Un élément est défini comme un champ, mais sans name, required ou path:

YAML
- 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​

Une source de données peut avoir plusieurs parseurs attachés. Chaque événement entrant est comparé aux parseurs dans l’ordre dans lequel ils sont déclarés et finit dans le premier parseur avec lequel il correspond. Un événement correspond lorsque ses champs requis sont présents, que ses champs typés sont convertis en types déclarés et que tous les validateurs réussissent. Les événements qui ne correspondent pas sont acheminés vers un sentinel de lettre morte au lieu de faire échouer le pipeline.

Analyseurs intégrés et personnalisés​

Lakewatch fournit des parseurs intégrés pour les sources de logs de sécurité courantes et vous permet de créer des parseurs personnalisés pour les sources qui ne sont pas couvertes ou que vous souhaitez personnaliser. Les deux utilisent le format YAML décrit ci-dessus.

Découvrir et inspecter les parsers intégrés​

Lorsque vous attachez des analyseurs à une source de données, vous pouvez parcourir les analyseurs intégrés disponibles et sélectionner ceux qui correspondent à votre source. Examinez un analyseur intégré pour voir les colonnes qu’il produit (ses champs, types, validateurs et observables) avant de l’attacher, afin de vérifier qu’il correspond aux événements que vous ingérez.

Les analyseurs intégrés sont en lecture seule. Pour personnaliser un analyseur, utilisez l’action Cloner sur l’analyseur afin de créer un analyseur personnalisé modifiable à partir de la définition de l’analyseur intégré, puis ajustez-le et enregistrez-le. Le clonage est une fonctionnalité de l’interface utilisateur qui copie la définition dans un nouvel analyseur personnalisé (version 1). Il ne s’agit pas d’une opération de clonage côté serveur, et l’analyseur intégré lui-même reste inchangé.

Créer un parser personnalisé​

Pour créer un analyseur personnalisé, fournissez un document YAML au format décrit ci-dessus et enregistrez-le dans un catalogue et un schéma Unity Catalog. La création d’un analyseur stocke la définition sous la version 1 et vous enregistre en tant que propriétaire de l’analyseur.

Définissez soigneusement vos champs, car un événement qui ne correspond à aucun analyseur est acheminé vers une sentinelle de lettres mortes plutôt que d’échouer le pipeline. Un événement dont les valeurs ne sont pas converties en types déclarés ou qui échoue à un validateur ne correspondra pas à l’analyseur.

Gestion des versions et suppression​

La modification d’un analyseur ajoute une nouvelle version immuable. Les versions existantes ne sont jamais modifiées et les numéros de version ne sont jamais réutilisés. Le serveur attribue à chaque nouvelle version le numéro suivant dans la séquence. Seul le propriétaire de l'analyseur peut ajouter une version.

Une source de données pin une version spécifique, de sorte qu’elle continue d’utiliser cette version jusqu’à ce que vous la changiez explicitement. Voir Modifier la version d’un analyseur.

Vous pouvez supprimer un parser personnalisé entier, ce qui supprime toutes ses versions. Il n'existe aucune opération pour supprimer une version individuelle. Seul le propriétaire peut supprimer un parser, et la suppression est bloquée tant qu’une source de données fait référence à une version du parser. Avant de supprimer, détachez le parser de chaque source de données qui l’utilise (remplacez chaque source de données par un autre parser et enregistrez la modification), puis supprimez le parser.

Limites​

Un document d'analyseur fait au maximum 256 Ko.