Steven's Knowledge

Dynamic Secrets

Generate short-lived database, cloud, and PKI credentials on demand - the real reason to run Vault

Dynamic Secrets

Static secrets are the obvious use of Vault. Dynamic secrets are the reason to run it. Instead of storing a long-lived password, you store the recipe to generate a credential, and Vault makes one on demand with a short TTL and an automatic revocation. The credential never outlives its purpose, so a leak is naturally bounded.

The Pattern

App ──► Vault ("give me a DB user")

            ├── Vault opens an admin connection
            ├── CREATE ROLE temp_xyz123 WITH LOGIN PASSWORD '...'
            │   VALID UNTIL now()+1h IN GROUP my_app_role

        Returns { username, password, lease_id, lease_duration: 3600 }


App connects to the DB with those creds

       1 hour later (or earlier if revoked)


Vault revokes: DROP ROLE temp_xyz123

You get four wins for free:

  1. No long-lived password. Even the database "doesn't know" the credentials before the request.
  2. Per-app, per-time-window auditing. Logs show which AppRole asked, when, and what lease was issued.
  3. Revocation is one CLI call. vault lease revoke -prefix database/creds/my-app.
  4. Forced rotation by design. If the lease is 1 hour, you've rotated 24 times a day without writing a cron.

Database Engine

Vault's database engine works with Postgres, MySQL, MongoDB, MSSQL, Oracle, Cassandra, Elasticsearch, and more.

Set Up

# Enable the database secrets engine
vault secrets enable database

# Configure connection (use a Vault-only admin user with CREATE ROLE rights)
vault write database/config/myapp \
  plugin_name=postgresql-database-plugin \
  allowed_roles="myapp-read,myapp-write" \
  connection_url="postgresql://{{username}}:{{password}}@db:5432/myapp?sslmode=disable" \
  username="vault_admin" \
  password="vault_admin_password"

# Define what "a credential for myapp-read" means
vault write database/roles/myapp-read \
  db_name=myapp \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}' INHERIT; \
                       GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

Use

vault read database/creds/myapp-read
Key                Value
---                -----
lease_id           database/creds/myapp-read/aB3Cd...
lease_duration     1h
lease_renewable    true
password           A1b2-C3d4-E5f6-...
username           v-myapp-read-9b3a4

The app connects with username + password. When the lease ends, Vault drops the role. Renew it if you need more time, up to max_ttl.

Rotate the Vault-Only Admin

The admin Vault uses to create roles is itself a secret. Rotate it on a schedule:

vault write -force database/rotate-root/myapp

Now even Vault doesn't know the admin password — it changed itself.

AWS / Cloud Credentials

Same shape for AWS IAM:

vault secrets enable aws

vault write aws/config/root \
  access_key=AKIA... \
  secret_key=...

vault write aws/roles/s3-readonly \
  credential_type=iam_user \
  policy_document=-<<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "*" }
  ]
}
EOF

vault read aws/creds/s3-readonly

Vault calls AWS, creates an IAM user with that inline policy, returns the access key + secret. Lease expires → user deleted.

For STS-based short-lived creds (preferred), use credential_type=assumed_role with a pre-existing IAM role.

PKI Engine — TLS Certificates on Demand

Vault can act as your internal CA, signing certs that live for hours:

vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki

# Generate the root CA (or import an existing one)
vault write -field=certificate pki/root/generate/internal \
  common_name="example.com" \
  ttl=87600h > ca.crt

# A role that defines what certs look like
vault write pki/roles/myapp \
  allowed_domains="example.com" \
  allow_subdomains=true \
  max_ttl="72h"

# Issue a cert
vault write pki/issue/myapp common_name="api.example.com" ttl="24h"

The response includes certificate, private_key, and ca_chain. Used for service-to-service mTLS without ever putting long-lived keys on disk.

Transit Engine — Encrypt-as-a-Service

Sometimes you don't want to store the secret in Vault — you want to encrypt your own data using Vault's keys:

vault secrets enable transit
vault write -f transit/keys/customer-data

# Encrypt
vault write transit/encrypt/customer-data \
  plaintext=$(echo -n "alice@example.com" | base64)
# → "ciphertext": "vault:v1:..."

# Decrypt
vault write transit/decrypt/customer-data \
  ciphertext="vault:v1:..."
# → "plaintext": "<base64 of alice@example.com>"

The plaintext never lands on Vault's disk. Useful for application-layer encryption — your DB stores vault:v1:... blobs, only Vault can decrypt them.

Lease Management

Every dynamic secret comes with a lease:

# See active leases
vault list sys/leases/lookup/database/creds/myapp-read

# Look at one
vault read sys/leases/lookup/database/creds/myapp-read/<lease-id>

# Renew (extend)
vault lease renew database/creds/myapp-read/<lease-id>

# Revoke (instant)
vault lease revoke database/creds/myapp-read/<lease-id>

# Revoke everything from a path (incident response)
vault lease revoke -prefix database/creds/myapp-read

The last one is the panic button. Something compromised? Revoke every credential issued for an app in one call.

A Working Recipe

A common production pattern:

  1. AppRole (or K8s auth, or AWS IAM auth) authenticates the workload to Vault.
  2. Policy grants read on database/creds/<role> and any static secrets the app needs.
  3. App fetches DB credentials at startup, opens its connection pool.
  4. App schedules a renewal loop on the DB lease; refreshes the connection pool when the lease nears expiry.
  5. Audit log records every credential issuance and renewal for forensics.

The infrastructure cost of doing this right is meaningful — but the security and compliance posture is in a different league.

What's Next

Best Practices — HA topology, unsealing strategies, K8s integration, audit, disaster recovery, and the operational story behind keeping Vault up.

On this page