Moving Beyond Static Secrets: Implementing Vault Dynamic Secrets
Stop managing static passwords. Learn how to use HashiCorp Vault Dynamic Secrets to generate on-demand, time-limited credentials that automatically expire, reducing the risk of credential leaks.
19 May 2026, 21:24 UTC

The Danger of the Long-Lived Password
Most applications rely on static credentials—a username and password stored in a config file or environment variable that remains valid for months or years. This creates a significant security gap: if a developer accidentally commits a secret to Git or a server is compromised, that credential remains a valid entry point until a human manually rotates it. In a large microservices architecture, rotating these passwords manually is often avoided because it risks breaking production dependencies.
The solution is Dynamic Secrets. Instead of storing a pre-existing password, HashiCorp Vault generates a unique, time-limited credential on the fly. When the application needs access to a database, it asks Vault for a lease. Vault creates a user in the database with the exact permissions required and hands those credentials to the app. When the lease expires, Vault automatically deletes the user from the database.
How Dynamic Secrets Work
Dynamic secrets shift the responsibility of credential lifecycle management from the developer to the infrastructure. This process relies on three core components:
- The Secrets Engine: A plugin (e.g., for PostgreSQL, AWS, or MongoDB) that knows how to communicate with the target system to create and delete users.
- The Role: A Vault configuration that defines the permissions the generated user should have (e.g.,
SELECTaccess to a specific schema). - The Lease: A time-to-live (TTL) attached to the secret. If the application doesn't renew the lease, the secret is revoked automatically.
Practical Example: Dynamic Database Credentials
To implement this, you must first configure Vault with administrative access to your database so it can manage users. This example assumes Vault is running and you have administrative permissions.
1. Enable the Database Engine
Run this on your Vault server or via the CLI with a valid token:
vault secrets enable database
2. Configure the Connection
Tell Vault how to connect to your database. Replace <DB_IP> and <ADMIN_USER> with your actual environment values. Risk: Ensure the admin user has CREATE USER permissions on the target database.
vault write database/config/my-postgres
plugin_name="postgres"
allowed_roles="readonly-role"
connection_url="postgresql://<ADMIN_USER>:<PASSWORD>@<DB_IP>:5432/postgres"
3. Define the Role
Create a role that defines the SQL statements Vault should execute to create the dynamic user. This ensures the application only gets the minimum necessary permissions.
vault write database/roles/readonly-role
db_name="my-postgres"
creation_statements="CREATE USER "{{name}}" WITH PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";"
default_ttl="1h"
max_ttl="24h"
4. Requesting a Secret
The application now requests credentials using the role name. Vault returns a username and password that did not exist a second ago.
vault read database/creds/readonly-role
Trade-offs and Limitations
While dynamic secrets eliminate the risk of leaked static passwords, they introduce new operational dependencies:
- Increased Latency: The application must make an API call to Vault before it can connect to the database, adding a small amount of overhead to the startup sequence.
- Database User Bloat: If TTLs are set too high or renewal logic fails, you may end up with a large number of orphaned users in your database until the cleanup process runs.
- Vault Availability: Vault becomes a critical path. If Vault is down, new instances of your application cannot obtain credentials to start, making a High Availability (HA) Vault cluster mandatory for production.
Verifying the Implementation
To verify the system is working, perform these three checks:
- Credential Validation: Use the credentials returned by
vault readto log into your database manually. - Permission Check: Attempt to perform a
DELETEorDROPoperation with the dynamic user; it should be rejected by the database. - Expiration Check: Note the
lease_id. Wait for the TTL to expire, then attempt to log in again. The database should reject the connection because the user has been deleted.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.