Gestion sécurisée des secrets pour agents IA — OpenBao embedded
MCP Vault est un serveur MCP qui fournit un coffre-fort de secrets pour les agents IA et les missions. Il embarque OpenBao (fork open-source de HashiCorp Vault, Linux Foundation) comme moteur de chiffrement.
Pensez 1Password, mais pour vos agents IA.
| Dashboard | Vaults & Secrets | Audit & Alertes |
|---|---|---|
![]() |
![]() |
![]() |
| Document | Description |
|---|---|
| ARCHITECTURE.md | Spécification complète — vision, architecture ASGI 5 couches, vaults, SSH CA, policies MCP (6 exemples prêts à l'emploi), sécurité des clés unseal (3 facteurs), roadmap HSM |
| TECHNICAL.md | Documentation technique — 14 modules source, modèle de données, Docker, 312 tests e2e, dépendances, roadmap |
| SECURITY_AUDIT.md | Rapport d'audit de sécurité consolidé — 60 findings V2.1, 28 corrigés, 13 résiduels documentés |
| scripts/README.md | Guide CLI complet — 7 groupes de commandes, shell interactif, exemples |
| tests/README.md | Guide d'exécution des tests — 4 niveaux, ~600 tests, commandes pour auditeurs |
| TEST_CATALOG.md | Catalogue des tests e2e — 15 catégories, 312 assertions, objectif de chaque section (pour auditeurs) |
# 1. Cloner et configurer
cp .env.example .env
# Adapter les credentials S3 dans .env
# 2. Build et démarrer
docker compose build
docker compose up -d
# 3. Vérifier (depuis le conteneur)
docker compose exec mcp-vault python scripts/mcp_cli.py health
# 4. Tester (312 tests e2e)
docker compose exec mcp-vault python tests/test_e2e.pyAu démarrage, MCP Vault :
- Charge les tokens depuis S3
- Restaure les données OpenBao (volume Docker ou S3)
- Démarre OpenBao, l'initialise (1ère fois) et le déverrouille
- Clés unseal : chiffrées (AES-256-GCM) sur S3, jamais en clair sur disque — uniquement en mémoire
- Active le sync S3 périodique (60s)
À l'arrêt (docker compose stop) :
- Scelle OpenBao 🔒
- Upload final vers S3 📤
- Arrête le processus — clés effacées de la mémoire
| Outil | Description |
|---|---|
system_health |
État de santé (OpenBao + S3) |
system_about |
Informations service (version, outils, plateforme) |
💡 Introspection : l'endpoint
/admin/api/whoamiet la commande CLIwhoamipermettent de vérifier l'identité et les permissions du token courant.
| Outil | Perm | Description |
|---|---|---|
vault_create(vault_id, description?) |
write | Crée un vault (mount KV v2) + métadonnées (owner, date) |
vault_list() |
read | Liste les vaults accessibles (filtrés par token) |
vault_info(vault_id) |
read | Détails d'un vault (métadonnées, secrets_count, owner) |
vault_update(vault_id, description) |
write | Met à jour la description d'un vault |
vault_delete(vault_id, confirm) |
admin | Supprime un vault et tous ses secrets |
| Outil | Perm | Description |
|---|---|---|
secret_write(vault_id, path, data, type?) |
write | Écrit un secret typé |
secret_read(vault_id, path, version?) |
read | Lit un secret (dernière version ou spécifique) |
secret_list(vault_id, path?) |
read | Liste les clés d'un vault |
secret_delete(vault_id, path) |
write | Supprime un secret et toutes ses versions |
secret_types() |
read | Liste les 14 types de secrets |
secret_generate_password(length?, ...) |
read | Génère un mot de passe CSPRNG |
Chaque vault possède sa propre CA SSH isolée — les CA sont cryptographiquement différentes entre vaults. Un certificat signé par la CA d'un vault ne fonctionne PAS sur les serveurs configurés pour un autre vault.
| Outil | Perm | Description |
|---|---|---|
ssh_ca_setup(vault_id, role, allowed_users?, ttl?) |
write | Configure une CA SSH + rôle dans un vault |
ssh_sign_key(vault_id, role, public_key, ttl?) |
read | Signe une clé publique → certificat éphémère |
ssh_ca_public_key(vault_id) |
read | Clé publique CA (pour TrustedUserCAKeys sur les serveurs) |
ssh_ca_list_roles(vault_id) |
read | Liste les rôles SSH CA configurés dans un vault |
ssh_ca_role_info(vault_id, role) |
read | Détails d'un rôle (TTL, allowed_users, extensions) |
Les policies permettent de restreindre finement les outils accessibles par token, avec support des wildcards (system_*, ssh_*...) et des règles par vault (prod-* → lecture seule).
| Outil | Perm | Description |
|---|---|---|
policy_create(policy_id, description?, allowed_tools?, denied_tools?, path_rules?) |
admin | Crée une policy avec règles d'accès |
policy_list() |
admin | Liste les policies avec compteurs |
policy_get(policy_id) |
admin | Détails complets (allowed/denied tools, path_rules) |
policy_delete(policy_id, confirm) |
admin | Supprime une policy |
📋 6 policies prêtes à l'emploi documentées dans ARCHITECTURE.md §6.4.1 :
readonly,ssh-operator,developer,prod-reader-dev-writer,ci-cd-agent,security-auditor
| Outil | Perm | Description |
|---|---|---|
token_update(hash_prefix, policy_id?, permissions?, vaults?) |
admin | Modifier un token existant (policy, permissions, vaults) |
| Outil | Perm | Description |
|---|---|---|
audit_log(limit?, client?, vault_id?, tool?, category?, status?, since?) |
admin | Journal d'audit filtrable (ring buffer 5000 entrées + JSONL persistant) |
💡 Workflow SSH CA typique (ex: infrastructure LLMaaS)
# 1. Setup initial (ONE-TIME) — créer vault + rôles SSH
vault_create("llmaas-infra", description="SSH CA LLMaaS")
ssh_ca_setup("llmaas-infra", "adminct", allowed_users="adminct", ttl="1h")
ssh_ca_setup("llmaas-infra", "agentic", allowed_users="agentic,iaagentic", ttl="30m")
# 2. Déployer la CA sur les serveurs (ONE-TIME)
result = ssh_ca_public_key("llmaas-infra")
# → Mettre result["public_key"] dans /etc/ssh/trusted-user-ca-keys.pem
# 3. Usage quotidien — signer une clé publique
cert = ssh_sign_key("llmaas-infra", "adminct", public_key="ssh-ed25519 AAAA...", ttl="1h")
# → cert["signed_key"] = certificat signé, valide 1h
# → OpenSSH l'utilise automatiquement si placé à côté de la clé privée| Type | Icône | Champs requis | Usage |
|---|---|---|---|
login |
🔑 | username, password | Identifiants web/app |
password |
🔒 | password | Mot de passe simple |
secure_note |
📝 | content | Notes sécurisées |
api_key |
🔌 | key | Clés API |
ssh_key |
🗝️ | private_key | Paires de clés SSH |
database |
🗄️ | host, username, password | Connexions BDD |
server |
🖥️ | host, username | Accès serveur |
certificate |
📜 | certificate, private_key | Certificats TLS/SSL |
env_file |
📄 | content | Fichiers .env |
credit_card |
💳 | number, expiry, cvv | Cartes bancaires |
identity |
👤 | name | Identités |
wifi |
📶 | ssid, password | Réseaux Wi-Fi |
crypto_wallet |
₿ | (tout optionnel) | Wallets crypto |
custom |
⚙️ | (champs libres) | Tout le reste |
Chaque secret supporte : tags, favorite, versioning KV v2 automatique.
⚠️ Seul le headerAuthorization: Bearer <token>est accepté. L'authentification par query string (?token=) a été supprimée pour des raisons de sécurité (v0.3.1).
Authorization: Bearer <token>
| Permission | Lecture | Écriture | Admin |
|---|---|---|---|
read |
✅ | ❌ | ❌ |
write |
✅ | ✅ | ❌ |
admin |
✅ | ✅ | ✅ |
3 couches d'isolation :
- Vault-level :
allowed_resources=[]→ owner-based (seuls les vaults créés par le token), ou liste explicite - Tool-level : policies avec
allowed_tools/denied_tools(wildcards fnmatch) - Path-level :
allowed_pathsdans lespath_rules→ contrôle par secret individuel
MCP Vault inclut un CLI complet avec Click + Rich + shell interactif :
# Commandes scriptables
python scripts/mcp_cli.py health
python scripts/mcp_cli.py about
python scripts/mcp_cli.py whoami # Identité du token courant
python scripts/mcp_cli.py vault list
python scripts/mcp_cli.py vault create serveurs-prod -d "Clés SSH prod"
python scripts/mcp_cli.py secret write serveurs-prod web/github -d '{"username":"me","password":"s3cr3t"}' -t login
python scripts/mcp_cli.py secret read serveurs-prod web/github
python scripts/mcp_cli.py secret password -l 32
python scripts/mcp_cli.py token create agent-sre --vaults prod --policy readonly
python scripts/mcp_cli.py token list
python scripts/mcp_cli.py policy create no-ssh -d "Pas de SSH" --denied "ssh_*"
python scripts/mcp_cli.py policy create team-x --allowed "secret_*" --path-rules '[{"vault_pattern":"shared-*","allowed_paths":["shared/*"]}]'
python scripts/mcp_cli.py audit --status denied --limit 10
# Shell interactif
python scripts/mcp_cli.py shellL'aide
--helpde chaque commande explique le modèle de sécurité à 3 couches et guide l'utilisateur.
Voir scripts/README.md pour la documentation complète du CLI.
📐 Documentation complète : le dossier
DESIGN/mcp-vault/contient la spécification détaillée (ARCHITECTURE.md — vision, sécurité, SSH CA, policies, roadmap HSM) et la documentation technique (TECHNICAL.md — modules, Docker, tests, dépendances).
Internet → WAF (Caddy + Coraza :8085) → MCP Vault (Python :8030) → OpenBao (:8200 localhost)
↕ OWASP CRS v4 ↕
Protection L7 S3 Dell ECS (persistance)
Le WAF protège l'API contre les attaques L7 (injections SQL, XSS, LFI, RCE, SSRF) :
- Caddy v2.11.2 compilé avec coraza-caddy v2.2.0 via
xcaddy - 24 règles OWASP CoreRuleSet v4.7.0 chargées
- Mode Blocking sur TOUS les endpoints (health,
/mcp,/admin/api) - 2 exclusions ciblées pour faux positifs JSON-RPC : Unicode français (920540), noms PowerShell (932120)
- Headers de sécurité : CSP, X-Frame-Options DENY, X-XSS-Protection, nosniff
- Méthodes autorisées adaptées au protocole MCP : GET, POST, DELETE, PUT, PATCH
AdminMiddleware → HealthCheckMiddleware → AuthMiddleware → LoggingMiddleware → FastMCP
STARTUP: S3 download → bao server → init/unseal → periodic sync
RUNTIME: secrets via hvac → sync S3 toutes les 60s
SHUTDOWN: seal → S3 upload final → stop process
CRASH: Docker volume local → redémarrage immédiat
Les clés unseal d'OpenBao sont protégées par séparation physique à 3 facteurs :
| Facteur | Stockage | Compromis seul = insuffisant |
|---|---|---|
| Données chiffrées (barrier OpenBao) | Volume Docker + S3 | Illisibles sans unseal key |
| Clés unseal (chiffrées AES-256-GCM) | S3 uniquement | Indéchiffrables sans bootstrap key |
| ADMIN_BOOTSTRAP_KEY | Variable d'env uniquement | Inutile sans les clés chiffrées |
Invariants : les clés unseal ne sont jamais en clair sur disque — uniquement en mémoire pendant le runtime. Un crash efface automatiquement les clés.
Roadmap sécurité :
| Version | Approche |
|---|---|
| v0.4.7 (actuel) | Clés sur S3 chiffrées AES-256-GCM+AAD, mémoire seule au runtime — 60 findings audités (28 corrigés, 13 résiduels documentés) |
| v1.0 | Transit Auto-Unseal via OpenBao dédié (KMS Cloud Temple) |
| v2.0 | Connexion HSM (Hardware Security Module) Cloud Temple — les clés ne quittent jamais le module matériel certifié |
📖 Voir DESIGN/mcp-vault/ARCHITECTURE.md §8 et §11 pour les détails complets.
📖 Voir tests/README.md pour le guide complet d'exécution.
# 1. Tests CLI — parsing + affichage (197 tests, SANS serveur)
python tests/test_cli_all.py
# 2. Tests CLI LIVE — cycle complet (79 tests, serveur réel)
MCP_URL=http://localhost:8085 MCP_TOKEN=<key> python tests/test_cli_live.py
# 3. Tests e2e MCP (312 tests, dans Docker)
docker compose exec mcp-vault python tests/test_e2e.py
# 4. Tests crypto (18 tests, SANS serveur — AES-256-GCM + AAD + validation entropie)
python tests/test_crypto.py
# Un seul groupe CLI
python tests/test_cli_all.py --only policy
# Un seul groupe e2e
docker compose exec mcp-vault python tests/test_e2e.py --test enforcement| Catégorie | Tests | Description |
|---|---|---|
| Système | 7 | health, about, services, tools_count (24) |
| Vault CRUD | 28 | create + métadonnées, list, info + owner, update, delete, confirm, erreurs |
| Secrets CRUD | 24 | 10 types écrits, read/list/delete, validation |
| Versioning | 8 | v1→v2→v3, read latest, read spécifique |
| Passwords | 14 | longueurs, options, exclusions, CSPRNG |
| Isolation | 7 | secrets cloisonnés entre vaults |
| Erreurs | 10 | edge cases, vault inexistant, type invalide, protection _vault_meta |
| S3 Sync | 3 | archive tar.gz sur S3 |
| SSH CA | 33 | setup, rôles multiples, signature ed25519, list/info roles, isolation CA, cleanup |
| Types | 14 | 14 types vérifiés individuellement |
| Admin API | 15 | health, whoami, generate-password, logs, unicité CSPRNG |
| Policies MCP | 43 | CRUD, validation, wildcards, path_rules, doublons, erreurs, Admin API REST |
| Policy Enforcement | 37 | check_policy, token_update, denied/allowed, changement policy, Admin API |
| Audit Log | 31 | audit_log MCP, filtres (category/tool/status/since/limit), stats, Admin API /audit |
| WAF Security | 17 | LFI, SQLi, XSS, RCE, Scanner Detection → 403 + non-régression requêtes légitimes |
mcp-vault/
├── .env.example # Configuration (copier en .env)
├── docker-compose.yml # WAF + MCP Vault + volumes
├── Dockerfile # Multi-stage (OpenBao 2.5.1 + Python 3.12)
├── requirements.txt # Dépendances Python
├── requirements.lock # Dépendances pinnées (versions exactes)
├── VERSION # 0.4.7
├── DESIGN/mcp-vault/
│ ├── ARCHITECTURE.md # Spécification détaillée (v0.2.2-draft)
│ ├── TECHNICAL.md # Documentation technique (v0.4.7)
│ └── SECURITY_AUDIT.md # Rapport d'audit consolidé (60 findings V2.1)
├── scripts/
│ ├── mcp_cli.py # CLI entry point
│ ├── README.md # Documentation CLI
│ └── cli/ # Module CLI (Click + Rich + prompt-toolkit)
│ ├── __init__.py # Config (.env, BASE_URL, TOKEN)
│ ├── client.py # MCPClient (Streamable HTTP)
│ ├── commands.py # 7 groupes Click
│ ├── display.py # Affichage Rich
│ └── shell.py # Shell interactif
├── src/mcp_vault/
│ ├── config.py # Configuration pydantic-settings
│ ├── server.py # FastMCP + 24 outils MCP + lifecycle + audit
│ ├── lifecycle.py # Orchestrateur startup/shutdown
│ ├── s3_client.py # Client S3 hybride SigV2/SigV4
│ ├── s3_sync.py # Sync file backend ↔ S3
│ ├── auth/ # Bearer tokens, check_access, ContextVar
│ ├── admin/ # Console web /admin + API REST
│ ├── openbao/ # Process manager, HCL config, lifecycle
│ ├── vault/ # Spaces, secrets, SSH CA, types
│ └── static/ # Console admin SPA (parité CLI 100%)
│ ├── admin.html # HTML structure + 7 modals
│ ├── css/admin.css # Design Cloud Temple (dark theme)
│ ├── js/ # 8 modules JS (config, api, app, dashboard, vaults, tokens, policies, activity)
│ └── img/ # logo-cloudtemple.svg
├── tests/
│ ├── README.md # Guide d'exécution des tests (auditeurs)
│ ├── TEST_CATALOG.md # Catalogue des tests pour auditeurs
│ ├── test_cli_all.py # 197 tests CLI parsing (sans serveur)
│ ├── test_cli_live.py # 79 tests CLI live (serveur réel)
│ ├── test_e2e.py # 312 tests MCP e2e (15 catégories)
│ ├── test_crypto.py # 18 tests AES-256-GCM + AAD
│ ├── test_service.py # 78 tests bas niveau
│ ├── test_integration.py # Tests pytest
│ └── cli/ # Tests CLI découpés par groupe (7 fichiers)
└── waf/ # WAF Caddy + Coraza (OWASP CRS v4)
├── Dockerfile # Multi-stage (xcaddy + CRS v4.7.0)
├── Caddyfile # Reverse proxy + coraza_waf
└── coraza.conf # Config Coraza + exceptions MCP
| Serveur | Rôle | Port |
|---|---|---|
| MCP Tools | Boîte à outils (SSH, HTTP, shell) | :8010 |
| Live Memory | Mémoire de travail partagée | :8002 |
| Graph Memory | Mémoire long terme (graphe) | :8080 |
| MCP Vault | 🔐 Coffre-fort à secrets | :8030 |
| MCP Agent | Runtime d'agents autonomes | :8040 |
| MCP Mission | Orchestrateur de missions | :8020 |
Licence : Apache 2.0 | Auteur : Cloud Temple | Version : 0.4.7


