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 tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn