Aller au contenu
Sécurité medium

Vault Database : credentials dynamiques pour PostgreSQL, MySQL, MongoDB

16 min de lecture

Vault Database secrets engine génère des credentials de base de données à la demande, avec une durée de vie limitée. Chaque service obtient son propre user/password, révocable individuellement.

Ce guide couvre PostgreSQL, MySQL et MongoDB, mais le principe s’applique à tous les plugins database supportés par Vault.

Pourquoi des credentials dynamiques pour les bases de données

Section intitulée « Pourquoi des credentials dynamiques pour les bases de données »
Modèle classiqueAvec Vault Database
Un compte partagé app_userUn compte par workload v-token-app-xyz
Password dans le code/envPassword généré à la demande
Rotation manuelle annuelleDynamic role : émission éphémère + révocation
Compromission = tout exposéCompromission = un seul workload
Audit : “app_user a fait X”Audit : “v-token-svc-abc a fait X”
  • Vault installé et démarré
  • Accès admin pour configurer le moteur
  • Base de données PostgreSQL, MySQL ou MongoDB accessible depuis Vault
  • Compte de gestion dédié à Vault pour créer/supprimer des utilisateurs
Architecture du moteur Database secrets de Vault : connexion, rôle et génération de credentials

Composants :

  • Connection : configuration de l’accès à la DB (URL, admin credentials)
  • Role : template SQL + TTL pour les credentials générés
  • Lease : référence au credential émis, pour renouvellement/révocation

Étape 1 : activer le moteur et configurer la connexion

Section intitulée « Étape 1 : activer le moteur et configurer la connexion »
Fenêtre de terminal
vault secrets enable database
Fenêtre de terminal
vault write database/config/postgres \
plugin_name="postgresql-database-plugin" \
allowed_roles="readonly,readwrite" \
connection_url="postgresql://{{username}}:{{password}}@postgres.example.com:5432/myapp?sslmode=require" \
username="vault_admin" \
password="VaultAdminPassword123"

Après configuration, faites tourner le mot de passe admin pour que seul Vault le connaisse :

Fenêtre de terminal
vault write -force database/rotate-root/postgres

Un rôle définit :

  • Le template SQL pour créer l’utilisateur
  • Les permissions accordées
  • Le TTL (durée de vie)
Fenêtre de terminal
vault write database/roles/readonly \
db_name="postgres" \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
revocation_statements="REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM \"{{name}}\"; \
DROP ROLE IF EXISTS \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"

Variables disponibles :

VariableDescription
{{name}}Username généré par Vault
{{password}}Password généré par Vault
{{expiration}}Date d’expiration (PostgreSQL VALID UNTIL)
Fenêtre de terminal
vault read database/creds/readonly

Sortie :

Key Value
--- -----
lease_id database/creds/readonly/abcd1234-5678-90ef
lease_duration 1h
lease_renewable true
password A1B2-c3D4-e5F6-g7H8
username v-token-readonly-xyz123abc

Ce qui se passe :

  1. Vault se connecte à PostgreSQL avec le compte admin
  2. Vault exécute le creation_statements avec un username/password générés
  3. Vault retourne les credentials et crée un lease
  4. L’application utilise ces credentials
  5. À expiration (ou révocation), Vault exécute revocation_statements
-- Lister les utilisateurs Vault
SELECT usename, valuntil FROM pg_user WHERE usename LIKE 'v-%';
-- Résultat
usename | valuntil
--------------------------+------------------------
v-token-readonly-xyz123 | 2026-03-16 15:00:00+00

Pour les applications legacy qui ne supportent pas les credentials dynamiques, Vault peut gérer un compte existant et le faire tourner automatiquement.

Fenêtre de terminal
vault write database/static-roles/legacy-app \
db_name="postgres" \
username="legacy_app_user" \
rotation_statements="ALTER ROLE \"{{name}}\" WITH PASSWORD '{{password}}';" \
rotation_period="24h"
Fenêtre de terminal
vault read database/static-creds/legacy-app

Sortie :

Key Value
--- -----
last_vault_rotation 2026-03-16T10:00:00Z
password NewRotatedPass123
rotation_period 24h
ttl 23h45m
username legacy_app_user

Différence avec dynamic role :

  • Le username est toujours le même (legacy_app_user)
  • Le password change automatiquement tous les rotation_period
  • Pas de lease à renouveler, mais le password change
Cas d’usageChoixRaison
Nouvelle applicationDynamic roleTraçabilité par workload
Appli legacy avec user fixe imposéStatic rolePas d’alternative
Besoin d’audit précis par serviceDynamic roleUsername unique = audit clair
Outil sans support de relecture credentialsStatic rolePassword stable entre rotations
Connexions éphémères (jobs, CI)Dynamic roleTTL très court possible
Connexion longue durée (pool)Dynamic role + renouvellementOu static role si legacy

Avant expiration, l’application peut prolonger :

Fenêtre de terminal
vault lease renew database/creds/readonly/abcd1234-5678-90ef

Le renouvellement est limité par le max_ttl du rôle.

Fenêtre de terminal
# Révoquer un credential spécifique
vault lease revoke database/creds/readonly/abcd1234-5678-90ef
# Révoquer tous les credentials d'un rôle
vault lease revoke -prefix database/creds/readonly

Action réelle : Vault exécute les revocation_statements et supprime l’utilisateur de la base de données.

Fenêtre de terminal
vault write -force database/rotate-role/legacy-app
policy-app-readonly.hcl
# Obtenir des credentials readonly
path "database/creds/readonly" {
capabilities = ["read"]
}
# Renouveler ses propres leases
path "sys/leases/renew" {
capabilities = ["update"]
}
Fenêtre de terminal
vault policy write app-readonly policy-app-readonly.hcl
import hvac
import psycopg2
from contextlib import contextmanager
def get_db_credentials():
"""Obtenir des credentials dynamiques depuis Vault."""
client = hvac.Client(url='https://vault.example.com')
# Auth via AppRole, Kubernetes, etc.
client.auth.approle.login(
role_id='app-role-id',
secret_id='app-secret-id'
)
# Lire les credentials dynamiques
creds = client.secrets.database.generate_credentials(
name='readonly',
mount_point='database'
)
return {
'user': creds['data']['username'],
'password': creds['data']['password'],
'lease_id': creds['lease_id'],
'lease_duration': creds['lease_duration']
}
@contextmanager
def get_db_connection():
"""Context manager avec credentials dynamiques."""
creds = get_db_credentials()
conn = psycopg2.connect(
host='postgres.example.com',
database='myapp',
user=creds['user'],
password=creds['password']
)
try:
yield conn
finally:
conn.close()
# Optionnel : révoquer immédiatement si TTL court
# client.sys.revoke_lease(creds['lease_id'])
# Utilisation
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users LIMIT 10")
rows = cursor.fetchall()

Pour les applications qui ne peuvent pas appeler Vault directement :

agent-config.hcl
template {
contents = <<EOF
[database]
host = postgres.example.com
port = 5432
database = myapp
{{ with secret "database/creds/readonly" }}
username = {{ .Data.username }}
password = {{ .Data.password }}
{{ end }}
EOF
destination = "/etc/myapp/db.conf"
perms = "0600"
command = "systemctl reload myapp"
}
SymptômeCause probableSolution
permission deniedPolicy manquanteVérifier database/creds/<role>
connection refusedVault ne peut pas joindre la DBVérifier réseau/firewall
authentication failedCredentials admin invalidesVérifier la config connection
role not foundRôle inexistant ou mal nommévault list database/roles
TTL exceeds maxTTL demandé > max_ttlRéduire le TTL ou augmenter max_ttl
User non supprimé après révocationrevocation_statements incorrectVérifier la syntaxe SQL
Fenêtre de terminal
# Vérifier la configuration
vault read database/config/postgres
# Tester une émission
vault read database/creds/readonly
# Vérifier les leases actifs
vault list sys/leases/lookup/database/creds/readonly
ResponsabilitéVaultVous
Créer des users dynamiques
Révoquer à expiration
Stocker les credentials✅ (le temps d’un lease)
Gérer le pool de connexions
Migrer les apps existantes
Monitorer les expirations❌*
Backup de la DB

*Vault expose des métriques, mais le monitoring est à votre charge.

  1. Dynamic role : nouveau credential par requête, traçabilité parfaite
  2. Static role : rotation périodique d’un compte existant (legacy uniquement)
  3. Connection : compte de gestion dédié à Vault (pas le superuser DB)
  4. rotate-root : après config, seul Vault connaît le mot de passe de gestion
  5. Lease : identifiant pour renouveler ou révoquer un dynamic credential
  6. Révocation : action réelle, l’user est supprimé de la DB
  7. Plugins : création_statements dépendent du moteur (PostgreSQL ≠ MongoDB)
  8. Intégration : l’app doit gérer renouvellement et rechargement des connexions

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn