Dynamic database credentials for Jenkins with Vault
Stop pasting Postgres passwords into Jenkins credentials. Vault mints a fresh user per build and revokes it when the job ends.
A static Postgres password pasted into Jenkins credentials is a secret with no expiry, shared by every build, that shows up in a heap dump the first time a job crashes. Vault's database secrets engine replaces it with a fresh user per build — created on demand, revoked when the lease ends.
Enable the database secrets engine
Point Vault at your database with an admin connection it uses only to mint and drop users. The allowed_roles list is the guardrail — this connection can't be used to create arbitrary roles.
vault secrets enable databasevault write database/config/appdb \plugin_name=postgresql-database-plugin \allowed_roles="jenkins-ci" \connection_url="postgresql://{{username}}:{{password}}@db:5432/app?sslmode=require" \username="vault_admin" password="$ADMIN_PW"
A role that mints short-lived users
The role defines the SQL Vault runs to create a user and the TTL before it's revoked. Keep the TTL just longer than your slowest build — minutes, not hours.
vault write database/roles/jenkins-ci \db_name=appdb \default_ttl="10m" max_ttl="20m" \creation_statements="\CREATE ROLE \"{{name}}\" LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";"
Read the role once and Vault hands back a brand-new username and password with a lease attached:
vault read database/creds/jenkins-ci Key Value--- -----lease_id database/creds/jenkins-ci/8Kx2..lease_duration 10mpassword A1a-9f3Kp2mZ-qX7username v-jenkins--ci-6Yh0 user auto-dropped when the 10m lease expiresWire it into the pipeline
The HashiCorp Vault plugin injects the secret as an env var scoped to a single stage. It never touches the Jenkins credential store and never lands on disk.
withVault(vaultSecrets: [[path: 'database/creds/jenkins-ci',secretValues: [[envVar: 'DB_USER', vaultKey: 'username'],[envVar: 'DB_PASS', vaultKey: 'password'],]]]) {sh './run-migrations.sh' // DB_USER / DB_PASS live only in this block}
Where this goes next
The same pattern extends to cloud IAM (aws secrets engine), PKI certificates, and SSH one-time passwords. Once builds stop carrying long-lived secrets, credential rotation becomes something Vault does for you instead of a quarterly fire drill.