Aller au contenu

Déployer Vault ou OpenBao pour supprimer les secrets en clair

Déployer Vault ou OpenBao pour supprimer les secrets en clair

Section intitulée « Déployer Vault ou OpenBao pour supprimer les secrets en clair »

Un mot de passe dans une variable d’environnement se lit dans /proc/<pid>/environ, un docker inspect ou la sauvegarde du serveur. Ce guide installe un coffre-fort de secrets (HashiCorp Vault, ou OpenBao, son dérivé sous licence libre MPL, Mozilla Public License, dont la commande bao accepte la même syntaxe) et y branche une application existante. La position défendue : un coffre ne vaut que par ses identifiants dynamiques et ses politiques étroites ; utilisé comme un fichier .env centralisé, il ajoute une panne possible sans retirer de risque.

→ Lire l’explication complète de la marmotte

Avant la première commande, il faut réunir :

  • trois machines Linux (le stockage intégré Raft exige un quorum, donc un nombre impair de nœuds) ;
  • un certificat TLS (Transport Layer Security) par nœud, émis par une autorité interne ; voir la section infrastructures à clés publiques et TLS ;
  • une source de descellement automatique : KMS (Key Management Service) d’un fournisseur cloud, ou un second coffre en mode transit. Le descellement par HSM (Hardware Security Module) via PKCS#11 (Public-Key Cryptography Standards n° 11) est réservé à l’édition Enterprise de Vault ; le fonctionnement d’un tel module est détaillé sur la page module cryptographique matériel et PKCS#11 ;
  • cinq personnes identifiées pour détenir les parts de récupération.

Le compromis : on gagne la révocation ciblée, la journalisation de chaque lecture et la rotation automatique ; on paie une dépendance de démarrage, car un coffre scellé ou injoignable bloque toutes les applications. Donc jamais de nœud unique hors laboratoire. Vingt ans de métier apprennent que le « serveur de secrets provisoire » a une espérance de vie supérieure à celle de l’équipe qui l’a monté.

Étapes 1 à 3 : installation, initialisation et descellement

Section intitulée « Étapes 1 à 3 : installation, initialisation et descellement »

Étape 1. Installer le binaire depuis le dépôt officiel de l’éditeur, puis écrire /etc/vault.d/vault.hcl avec un bloc storage "raft", un listener "tcp" en TLS, api_addr, cluster_addr et un bloc seal "awskms" (ou gcpckms, azurekeyvault, transit).

Étape 2. Initialiser une seule fois, sur le premier nœud. Avec un descellement automatique, l’initialisation ne produit pas de clés de descellement mais des clés de récupération, découpées par le partage de secret de Shamir : elles servent à régénérer un jeton racine, pas à ouvrir le coffre au quotidien.

Étape 3. Vérifier le redémarrage. Un coffre en descellement manuel repart scellé à chaque redémarrage : trois porteurs de parts doivent alors se connecter, un dimanche, pour que la production reparte. C’est l’erreur de configuration la plus fréquente, et elle ne se voit qu’au premier redémarrage non planifié. Le descellement automatique déplace la confiance vers le KMS : quiconque peut appeler Decrypt sur cette clé peut desceller le coffre. La politique d’accès à la clé KMS fait donc partie du périmètre du coffre.

Le jeton racine produit à l’initialisation doit être révoqué dès que les méthodes d’authentification et les politiques d’administration existent. Il se régénère au besoin avec operator generate-root et le quorum de clés de récupération.

Commandes reproductibles : politique, AppRole et rotation PostgreSQL

Section intitulée « Commandes reproductibles : politique, AppRole et rotation PostgreSQL »

Le bloc suivant enchaîne les étapes 4 à 7 pour une application facturation adossée à PostgreSQL. Il suppose VAULT_ADDR et un jeton d’administration exportés.

Fenêtre de terminal
# Étape 2 : initialisation avec 5 parts de récupération, seuil de 3
vault operator init -recovery-shares=5 -recovery-threshold=3
# Journal d'audit : sans lui, aucune lecture de secret n'est tracée
vault audit enable file file_path=/var/log/vault/audit.log
# Étape 4 : politique limitée aux identifiants de cette seule application
cat > facturation.hcl <<'EOF'
path "database/creds/facturation" {
capabilities = ["read"]
}
EOF
vault policy write facturation facturation.hcl
# Étape 5 : identité machine AppRole, secret_id à usage unique, jeton court
vault auth enable approle
vault write auth/approle/role/facturation \
token_policies="facturation" token_ttl=1h token_max_ttl=4h \
secret_id_ttl=10m secret_id_num_uses=1 \
token_bound_cidrs="10.20.0.0/24"
# Étape 6 : moteur de base de données, puis rotation du mot de passe
# d'amorçage pour que plus aucun humain ne le connaisse
vault secrets enable database
vault write database/config/pg-facturation \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@pg.interne:5432/facturation?sslmode=verify-full" \
username="vault_admin" password="mot-de-passe-initial" \
allowed_roles="facturation"
vault write -force database/rotate-root/pg-facturation
# Étape 7 : rôle dynamique, compte PostgreSQL créé à la demande, 1 h de vie
vault write database/roles/facturation db_name=pg-facturation \
creation_statements="CREATE ROLE \"{{name}}\" LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl=1h max_ttl=24h

Côté application, la variable DB_PASSWORD disparaît. Le script de démarrage échange le couple role_id et secret_id contre un jeton, puis lit des identifiants frais :

Fenêtre de terminal
# Au démarrage : authentification AppRole, puis lecture d'un compte éphémère
TOKEN=$(curl -s --cacert /etc/ssl/ca-interne.pem \
--data "{\"role_id\":\"$ROLE_ID\",\"secret_id\":\"$SECRET_ID\"}" \
"$VAULT_ADDR/v1/auth/approle/login" | jq -r .auth.client_token)
curl -s --cacert /etc/ssl/ca-interne.pem -H "X-Vault-Token: $TOKEN" \
"$VAULT_ADDR/v1/database/creds/facturation" | jq '.data, .lease_duration'

Vault Agent renouvelle le bail (lease) et réécrit un fichier de configuration par gabarit, sans toucher au code. Pour un compte qui doit rester fixe, un rôle statique (database/static-roles/..., rotation_period=24h) fait tourner le mot de passe du même compte.

Le coffre ne résout pas le problème du secret zéro : le secret_id doit arriver jusqu’à l’application par un canal de confiance (orchestrateur, emballage de réponse à usage unique avec -wrap-ttl). Un secret_id réutilisable posé dans le dépôt Git ramène au point de départ, avec une API (Application Programming Interface) en plus.

Les attaques connues visent le jeton racine oublié, les parts de récupération détenues par une seule personne, la clé KMS trop partagée et les politiques path "secret/*" écrites « le temps de tester ». Contre-mesures : aucun joker hors de l’espace de l’application, politiques versionnées et relues, alerte sur toute création de jeton racine.

Ce que le coffre ne garantit pas : une application compromise lit légitimement ses propres secrets, et le coffre servira poliment l’attaquant installé dans le processus. Le cloisonnement vient des politiques par application et de la durée de vie courte, pas du chiffrement. La relation avec la gestion des identités machine est développée dans la section identités.

Piège d’exploitation : si tous les journaux d’audit échouent à écrire (disque plein), Vault refuse toute requête. Un second périphérique d’audit (socket vers le collecteur central) évite cet arrêt.

Le coffre sauvegarde les secrets des autres ; personne ne sauvegarde le coffre. Avec Raft, la commande vault operator raft snapshot save coffre-$(date +%F).snap produit un instantané chiffré par la barrière du coffre. Deux conséquences : l’instantané peut quitter le site sans exposer les secrets, et il est inutilisable sans l’accès à la clé KMS de descellement ou aux clés de récupération. Sauvegarder l’instantané sans documenter l’accès au KMS revient à archiver un coffre dont la combinaison a été jetée avec le carton. La restauration (snapshot restore) se teste sur un cluster isolé.

Sans coffre-fort, les identifiants vivent en clair dans les fichiers de configuration, les variables d’environnement et les images de conteneurs : toute personne disposant d’un accès en lecture au dépôt, d’un droit de listage des processus ou d’un export de sauvegarde obtient le mot de passe de production tel quel. Rien n’horodate l’usage d’un secret : impossible de savoir quel service, quelle machine ou quel compte s’en est servi, ni de distinguer un accès légitime d’un accès détourné. La rotation devient un chantier manuel, donc reportée, et un secret compromis reste valide des mois. En cas de fuite avérée, il n’existe aucun périmètre à révoquer : il faut changer le mot de passe partout à l’aveugle, redémarrer chaque consommateur et espérer n’en avoir oublié aucun. La reprise se mesure alors en interruptions de service, pas en appels d’API.

Une application a besoin de mots de passe pour parler à sa base de données. Souvent, ces mots de passe sont écrits en clair dans un fichier ou dans les réglages du programme, où n’importe qui ayant accès à la machine peut les lire. Un coffre de secrets est un logiciel installé sur plusieurs serveurs qui garde ces mots de passe chiffrés. Au démarrage, le coffre est verrouillé : il faut une clé principale pour l’ouvrir. Cette clé est soit découpée en cinq morceaux confiés à cinq personnes (trois suffisent pour la reconstituer), soit confiée à un service de clés externe qui ouvre le coffre tout seul à chaque redémarrage. Ensuite, chaque application prouve son identité avec deux codes, et reçoit un droit d’accès qui ne dure qu’une heure. Une règle écrite à l’avance dit exactement quels secrets elle peut lire. Pour la base de données, le coffre fabrique même un compte neuf à chaque demande et le supprime à l’expiration : un mot de passe volé devient vite inutile. Chaque lecture est inscrite dans un journal. Si le coffre reste verrouillé ou tombe, plus aucune application ne démarre. Il faut donc le sauvegarder et garder de quoi le rouvrir.

À lire aussi

Pages voisines