Aller au contenu principal

A14 - Gestion des incidents

GroupeTechnologieStatutServicePhase de la feuille de routeContrats
A - Gouvernance, identité et sécuritéDéveloppé + SIEMà développerincidents10audit-event

Retour à l'index - English

Rôle et responsabilités​

Cycle de vie des incidents IA et actions de confinement (suspension agent/modèle/provider, rotation de clé), envoi au SIEM.

SOC et AI-SDR (section 11 du kit, domaine eai.domains.soc) : les détections des sources internes et externes sont normalisées, corrélées par utilisateur, agent ou tenant en un incident de catégorie soc, évaluées par le moteur de risque (sévérité, confiance, raisons dans la chronologie), puis traitées uniquement par des réactions typées (/v1/soc/orders) via le moteur de politique de réponse et sa garde de proportionnalité. Chaque confinement est une ligne du registre des kill switches (eai.kill_switches, état voulu et état observé) appliquée par le point de décision de politique, l'authentification et le runtime des agents, et ne devient SUSPENDED_VERIFIED que sur un reçu. La reprise exige deux approbateurs distincts et une ré-autorisation ; les preuves d'incident sont scellées avec une chaîne de possession. Procédure : SOC, Kill Switch et reprise.

Modèle de données​

Tables (schéma eai, chaque table tenant porte tenant_id uuid NOT NULL avec une politique RLS sur current_setting('app.tenant_id', true)::uuid) : eai.incidents, eai.incident_actions, eai.audit_events.

Endpoints API​

  • GET /v1/incidents
  • POST /v1/incidents
  • GET /v1/incidents/{id}
  • PATCH /v1/incidents/{id}
  • POST /v1/incidents/{id}/actions
POST /v1/incidents HTTP/1.1
Host: <control-plane-host>
X-API-Key: eai_xxx_secret
Accept-Language: fr
Content-Type: application/json

{"title": "Invoice agent returns PII in answers", "severity": "high", "category": "data_leak", "description": "Customer emails appear in agent responses"}
{
"id": "3421a88d-c114-4b2c-9ec0-addc883aefbd",
"tenant_id": "18de5695-21f9-4053-a4ea-beb4bf2a5932",
"title": "Invoice agent returns PII in answers",
"description": "Customer emails appear in agent responses",
"severity": "sev2",
"status": "open",
"category": "data_leak",
"resources": [],
"assignee": null,
"created_by": "alice",
"created_at": "2026-10-30T01:35:52.825765Z",
"updated_at": "2026-10-30T01:35:52.825765Z",
"resolved_at": null,
"timeline": [
{"kind": "created", "message": "incident opened with severity sev2", "data": {"severity": "sev2", "resources": []}, "actor": "alice", "at": "2026-10-30T01:35:52.828583Z"}
],
"actions": []
}

Les erreurs utilisent l'enveloppe commune {"error": {"code", "message", "message_i18n", "details", "request_id"}} ; les listes sont paginées avec limit et cursor.

Utilisation des SDK​

Python (enterprise_ai):

from enterprise_ai import EnterpriseAI

client = EnterpriseAI(base_url="<control-plane-url>", api_key="eai_xxx_secret")
items = client.incidents.list()

TypeScript (@enterprise-ai/sdk):

import { EnterpriseAI } from "@enterprise-ai/sdk";

const eai = new EnterpriseAI({ baseUrl: "<control-plane-url>", apiKey: process.env.EAI_API_KEY });
const items = await eai.incidents.list();

Java (enterprise-ai-java):

EnterpriseAIClient client = EnterpriseAIClient.builder()
.baseUrl("<control-plane-url>")
.apiKey(System.getenv("EAI_API_KEY"))
.build();
var items = client.incidents().list();

Go (enterprise-ai-go):

client, _ := eai.NewClient(eai.WithBaseURL("<control-plane-url>"), eai.WithAPIKey(os.Getenv("EAI_API_KEY")))
items, err := client.Incidents.List(ctx)

Configuration​

  • Environnement : EAI_DATABASE_URL, EAI_OTEL_EXPORTER_OTLP_ENDPOINT.
  • Valeurs Helm : controlPlane.enabled, controlPlane.replicas, controlPlane.resources, controlPlane.config.

Contrôles de sécurité​

  • Authentification par JWT OIDC, clé API tenant avec scopes, ou mTLS SPIFFE ; le tenant est résolu depuis l'identifiant, jamais depuis le corps.
  • Autorisation par décisions OpenFGA et OPA ; chaque mutation et décision écrit une ligne eai.audit_events chaînée par hash.
  • Les secrets ne sont jamais renvoyés par l'API ; TLS partout ; les politiques réseau Cilium restreignent qui peut joindre le service.

Observabilité​

  • Métriques : eai_incident_management_requests_total, eai_incident_management_errors_total, eai_incident_management_latency_seconds (Prometheus).
  • Traces : spans OpenTelemetry eai.incidents.* avec propagation W3C traceparent, spans IA envoyés à Opik.
  • Actions d'audit : incident.create, incident.update, policy.evaluate.

Aspects FinOps​

Le coût d'exploitation est imputé par tenant et projet via les labels des Usage Events et les requêtes de ressources Kubernetes ; pas de coût direct par appel.

Modes de défaillance et résilience​

  • Réplicas sans état derrière l'API Gateway, PostgreSQL HA pour l'état ; la sonde GET /readyz retire les pods défaillants.
  • Système externe indisponible : échec fermé pour les décisions de sécurité, code d'erreur explicite, aucun contournement silencieux.

Adoption autonome (client d'un client)​

Un client d'un client peut adopter cette brique seule avec le sous-client SDK Python client.incidents (TS eai.incidents, Java client.incidents(), Go client.Incidents). Déploiement minimal : Control Plane API + PostgreSQL + Keycloak (ou clés API), le Control Plane charge tous les domaines de services/control-plane/src/eai/domains ; les composants optionnels du chart se coupent dans deploy/helm/enterprise-ai/values.yaml (vllm.enabled, qdrant.enabled, nats.enabled, workers.enabled).

Tests d'acceptation​

  1. Un tenant ne peut ni lire ni modifier les ressources d'un autre tenant (test RLS).
  2. Chaque mutation produit un événement d'audit vérifiable par GET /v1/audit/verify.
  3. Les erreurs sont renvoyées en anglais et en français selon Accept-Language.