Files
chlova/docs/security.md
T
Kantin-Petit 0f63b3addd feat: socle sécurité — socket-proxy, réseaux, egress (v0.3.0)
Modèle de menace centré prompt-injection + défenses par couche
(surface réduite, socket-proxy obligatoire, scoping tokens, egress
ollama.com only, secrets par référence, lecture seule renforcée, audit).
Documente réseaux interne/egress et filtrage Docker en lecture seule P1.
Normalise les fins de ligne (.gitattributes).

Palier de risque : n/a (doc + conventions).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 01:00:45 +02:00

3.4 KiB

Sécurité CHLOVA

Non négociable. Risque n°1 : la prompt injection. L'agent a un accès quasi-root via Portainer — le modèle de menace part du principe qu'une entrée hostile peut détourner l'agent.

Modèle de menace

  • Prompt injection : une donnée lue (message, contenu de workflow, log) tente de faire exécuter à l'agent une action non voulue.
  • Exfiltration de secrets : l'agent ne doit jamais voir de secret en clair.
  • Escalade : reclasser un asset privilégié en réversible pour contourner la review. Interdit par construction (voir risk-tiers.md).
  • Exposition réseau : une brique interne deviendrait joignable de l'extérieur.

Défenses (par couche)

1. Réduction de la surface

  • Seul le backend CHLOVA est exposé (auth + TLS). Ollama, n8n, Portainer et les serveurs MCP n'écoutent que sur chlova-internal. Voir infra/networks.md.
  • Phase 1 : surface Telegram en long-pollingaucun port publié.

2. Accès Docker via socket-proxy (obligatoire)

  • Jamais de /var/run/docker.sock monté dans l'agent ou le MCP Portainer.
  • tecnativa/docker-socket-proxy filtre les endpoints Docker autorisés.
  • Phase 1 (lecture seule) : n'autoriser que les endpoints de lecture (CONTAINERS=1, IMAGES=1, NETWORKS=1, VOLUMES=1, INFO=1, VERSION=1) et interdire tout le reste (POST=0, EXEC=0, CONTAINERS_CREATE absent…). Détail dans infra/socket-proxy/README.md.

3. Scoping des tokens

  • Token n8n : portée minimale (lecture en P1).
  • Token Portainer : portée minimale + PORTAINER_READ_ONLY=true en P1 (le serveur MCP annote readOnlyHint et réécrit les secrets en [REDACTED] avant qu'ils n'atteignent le modèle).
  • Un token = un usage. Rotation documentée.

4. Egress filtré

  • Sortie réseau par défaut refusée pour les conteneurs de l'agent.
  • Seule exception : ollama.com (proxy cloud Ollama). À appliquer au niveau pare-feu hôte / réseau Docker. Voir infra/networks.md.

5. Secrets par référence

  • Tous les secrets (dont OLLAMA_API_KEY) via variables d'env / coffre, jamais en dur. .env n'est jamais commité (.env.example fait foi des clés requises).
  • L'agent manipule des références, pas des valeurs. config.ts plante au boot (fail-closed) si un secret requis manque.

6. Lecture seule renforcée (Phase 1)

  • Le readonly-filter de l'orchestrateur n'expose au LLM que les outils MCP readOnlyHint=true. Les outils mutants ne sont pas branchés. Double barrière avec le PORTAINER_READ_ONLY=true côté serveur MCP.

7. Audit

  • Toute opération mutante est audit-loggée (qui/quoi/quand/résultat). En P1, toute exécution d'outil est tracée même si read-only.
  • Déploiements de stacks en GitOps dès que possible (rollback + audit gratuits).

Invariants vérifiés par test

  • Aucun outil non-read-only n'est exposé en Phase 1 (readonly-filter.test.ts).
  • Un asset privileged ne peut pas être reclassé reversible (gatekeeper.test.ts).
  • config.ts refuse de démarrer si un secret requis manque.

Checklist de revue avant tout passage en Phase 2 (écriture)

  • socket-proxy en place, endpoints d'écriture toujours refusés tant que non requis
  • gatekeeper câblé (vérif statut avant exécution)
  • egress toujours limité à ollama.com
  • audit log couvre toute opération mutante
  • tokens re-scopés au strict besoin de la capacité ajoutée