SIEM, audit des mutations, WORM et effacement
Envoi au SIEM (job siem_forward)
Le worker (python -m eai.worker) lit la piste d'audit chaînée (eai.audit_events) de chaque tenant après un
filigrane (eai.siem_cursors, migration V096) et transmet les événements de sécurité avec
eai.domains.incidents.siem.forward : syslog RFC 5424 (UDP ou TCP) et webhook HTTP JSON.
- Sélection :
EAI_SIEM_FORWARD_ACTIONS, motifs séparés par des virgules (prefix.*ou nom exact,*pour tout l'audit). Valeur par défaut :security.*(échecs d'authentification, injections de prompt, refus de sortie, limitation de débit),policy.*,incident.*,approval.*,secret.*,api_key.*,audit.*,dlp.*,member.*,authz.write,authz.delete, et les coupe-circuitsprovider.disable,model.disable,agent.kill,agent.suspend. Les refus (decision.result = deny) et les échecs (outcome = failureouerror) sont toujours transmis. - Reprise : le filigrane n'avance qu'au-delà des événements acceptés par toutes les cibles. Un échec arrête le
lot du tenant, l'erreur est enregistrée dans
eai.siem_cursors.last_erroret danseai.worker_jobs, et le passage suivant reprend au premier événement non transmis. Avec plusieurs cibles, une cible déjà servie peut recevoir le même événement une seconde fois (au moins une fois par cible) ;event_idpermet la déduplication. - Bornes :
EAI_SIEM_FORWARD_BATCH(500) événements par tenant et par passage,EAI_WORKER_SIEM_FORWARD_SECONDS(30) entre deux passages. - Format :
<pri>1 <horodatage> <hôte> eai-control-plane - audit - {json}, le JSON commence par"schema":"eai.audit.v1"puis porte l'Audit Event v1 (action,outcome,decision,actor,tenant_id,resource,evidence,hash). Sévérité syslog : erreur pour les échecs, refus et blocages, avertissement poursecurity.*,incident.*,secret.*,audit.*, notice sinon. Le webhook reçoit{"event": ..., "sourcetype": "eai:audit"}.
Wazuh
Choix retenu : Wazuh n'est pas déployé par la plateforme (ni dans le chart, ni dans l'ApplicationSet). C'est le SIEM
du client, joint en syslog TCP par EAI_SIEM_WAZUH_HOST / EAI_SIEM_WAZUH_PORT / EAI_SIEM_WAZUH_PROTO=tcp. Un
SIEM n'a de valeur que hors du périmètre qu'il surveille ; l'exploiter dans le même cluster ferait perdre la trace
d'une compromission de ce cluster. Les autres SIEM (Splunk HEC, Elastic) passent par EAI_SIEM_WEBHOOK_URL.
Fichiers fournis dans deploy/wazuh :
manager-ossec.conf: écoute syslog distante (<remote>) à fusionner dans/var/ossec/etc/ossec.conf, en restreignantallowed-ipsà la plage de sortie du worker.decoders/eai_audit_decoders.xml: préfiltreeai-control-plane - <msgid> -suivi de{"schema":"eai.audit.v1", puisJSON_Decoderà partir de la fin du préfiltre.rules/eai_audit_rules.xml(100800 à 100814) : coupe-circuits, échecs et rafales d'échecs par tenant, injection de prompt, révocation ou rotation de clé, rupture de chaîne d'audit (audit.chain_verify_failed, émis par le jobverify_chain), droits accordés, approbation rejetée, échecs d'authentification et force brute par adresse, refus de sortie, réponse à incident, changement de configuration de sécurité, limitation de débit.agent-ossec.conf: agent des hôtes OpenBao uniquement (journal d'audit fichier d'OpenBao).
tests/test_siem_audit_worm.py vérifie que chaque règle vise une action réellement émise par le code et que les
valeurs outcome attendues existent (success, failure, error).
Audit de chaque mutation
tests/test_audit_mutation_coverage.py énumère toutes les routes POST, PUT, PATCH et DELETE et échoue si l'une
d'elles n'atteint pas audit() (ou security_event()) dans son graphe d'appels. Les exemptions sont listées avec
leur justification (routes en lecture seule : resolve, simulate, context/plan, render, validate ; webhook
entrant journalisé dans eai.webhook_deliveries).
Routes à haute fréquence :
| Route | Événement | Volume |
|---|---|---|
POST /v1/runs/{run_id}/heartbeat | run.heartbeat | changement d'état seulement : premier battement du run, ou réponse stop |
POST /v1/sessions/{session_id}/messages | session.message.add | un par message, rôle et longueur, jamais le contenu |
POST /v1/finops/usage | finops.usage.ingest | un par appel, sans la charge utile |
POST /v1/finops/usage/batch | finops.usage.ingest_batch | agrégé : un par lot avec sa taille |
POST /v1/quotas/reserve, /commit, /release | finops.quota.reserve, .commit, .release | un par appel |
POST /v1/finops/gpu/samples | finops.gpu.samples_ingest | agrégé : un par lot d'échantillons |
Les producteurs d'usage à fort débit doivent utiliser la route batch. Les réservations internes de la passerelle
LLM ne passent pas par ces routes et ne génèrent pas d'événement supplémentaire.
Export WORM périodique (job audit_worm)
Chaque jour UTC complet de chaque chaîne de tenant non encore exporté donne un NDJSON et un manifeste signés,
écrits avec verrouillage d'objet S3 (EAI_AUDIT_WORM_RETENTION_DAYS, 365) sous
tenants/<tenant>/audit-worm/<export_id>. L'export est consigné dans eai.audit_exports et eai.audit_worm_days
(un jour n'est jamais réexporté) et audité (audit.export). Au plus 200 exports par passage, l'arriéré continue au
passage suivant. La logique est commune avec POST /v1/audit/export
(eai.domains.observability.audit_api.write_export).
Signature (EAI_AUDIT_SIGNING) :
transit: OpenBao Transitsignsur l'empreinte SHA-256 avec la cléEAI_OPENBAO_AUDIT_SIGNING_KEY(eai-audit-export, typeed25519ouecdsa-p256), vérifiable partransit/verify. La clé privée ne quitte jamais OpenBao. Création :bao write transit/keys/eai-audit-export type=ed25519, politique du Control Plane limitée àtransit/sign/eai-audit-exportettransit/verify/eai-audit-export.hmac: HMAC-SHA256 dérivé de la clé maître, réservé au développement et aux tests.auto(défaut) : Transit si OpenBao est configuré, HMAC sinon.
En production, le contrôle de démarrage (eai/security/startup.py) refuse de démarrer sans EAI_OPENBAO_URL et
EAI_OPENBAO_TOKEN, ou avec EAI_AUDIT_SIGNING=hmac.
Effacement d'une personne
POST /v1/retention/erase couvre aussi les stockages externes, rapportés dans external :
- Opik : traces dont la métadonnée
eai.subject_hashest l'empreinte pseudonyme de la personne, listées parGET /v1/private/traces(filtre de métadonnée) puis supprimées parPOST /v1/private/traces/delete(eai/integrations/opik.py, 10 000 traces par demande au plus,truncatedsinon). - ClickHouse :
DELETEléger des lignes d'usage (user_id) et des spans des sessions de la personne ; valeurs passées en paramètres typés. La ligne d'usage PostgreSQL reste conservée comme pièce financière. - Statut par stockage :
not_configured,dry_run,completedouerror. Une erreur rend la demandeincompleteet l'événementretention.eraseest écrit avecoutcome = failure: relancer la demande. - Un gel juridique sur la personne bloque toute la demande (
blocked_legal_hold), stockages externes compris.
Réglages
| Variable | Défaut | Rôle |
|---|---|---|
EAI_SIEM_SYSLOG_HOST, _PORT, _PROTO | collecteur syslog | |
EAI_SIEM_WAZUH_HOST, _PORT, _PROTO | écoute syslog du manager Wazuh | |
EAI_SIEM_WEBHOOK_URL, _TOKEN, _AUTH_SCHEME | webhook HTTP JSON | |
EAI_SIEM_FORWARD_ACTIONS | voir plus haut | sélection des événements |
EAI_SIEM_FORWARD_BATCH | 500 | événements par tenant et par passage |
EAI_WORKER_SIEM_FORWARD_SECONDS | 30 | intervalle du job siem_forward |
EAI_WORKER_AUDIT_WORM_SECONDS | 3600 | intervalle du job audit_worm |
EAI_AUDIT_WORM_RETENTION_DAYS | 365 | durée du verrouillage d'objet |
EAI_AUDIT_SIGNING | auto | auto, transit ou hmac |
EAI_OPENBAO_AUDIT_SIGNING_KEY | eai-audit-export | clé Transit de signature |
Audit Gateway et Evidence Service (section 11 du kit)
- Jobs du worker :
audit_gateway(boîte d'envoi versEAI_AUDIT_GATEWAY_HTTP_URLet NATS JetStream),audit_seal(sceaux Ed25519),audit_integrity(recalcul et alertes),audit_retention(purge des charges chiffrées hors conservation légale). Réglages : configuration.md. - Récupérer les binaires de test :
bash tools/audit/fetch.sh(nats-server 2.15.2, sha256 épinglé, dans/tmp/toolchains). - Vérifier hors ligne :
GET /v1/evidence/bundlepuispython -m eai.domains.evidence.verify bundle.json(code 0 : valide, 1 : altération). - Alerte d'intégrité :
GET /v1/evidence/alerts?status=open; ne jamais réparer la ligne, ouvrir un incident et conserver la preuve. - Modèle de sécurité : ../security/audit-evidence.md.