Vault’s secrets engines are more than just key-value stores; they’re dynamic credential generators that can issue, revoke, and manage secrets on demand.

Let’s see this in action with the kv secrets engine. Imagine you need a static secret, like an API key or a database password, that doesn’t change often.

vault secrets enable -path=secret kv
vault kv put secret/myapp username="admin" password="supersecretpassword123"

Now, when your application needs these credentials, it can read them:

vault kv get secret/myapp

The output would look something like:

====== Secret Path: secret/myapp ======
Key      Value
---      ---
password supersecretpassword123
username admin

This is the simplest form. But Vault’s power lies in its dynamic secrets engines. Consider the database secrets engine. Instead of storing a static database user and password, Vault can generate a unique, temporary user and password for each application that requests it.

vault secrets enable database
vault write database/config/my-postgres \
    plugin_name=postgresql-database-plugin \
    connection_url="postgresql://vault:vaultpassword@localhost:5432/mydatabase?sslmode=disable" \
    allowed_roles="readonly,readwrite"

vault write database/roles/readonly \
    db_name=my-postgres \

    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiry}}';" \

    default_ttl="1h" \
    max_ttl="24h"

Now, when an application needs database access, it asks Vault:

vault read database/creds/readonly

Vault will connect to your PostgreSQL database, create a new role (user) with a randomly generated password, and return those credentials along with an expiry time.

====== Secret Path: database/creds/readonly ======
Key        Value
---        ---
password   a_randomly_generated_password_here
role_name  readonly_a_unique_id_generated_by_vault
username   readonly_a_unique_id_generated_by_vault

Once the default_ttl of 1 hour expires, Vault automatically revokes the database user. This drastically reduces the risk of compromised static credentials.

Vault offers several built-in secrets engines, each tailored for different use cases:

  • KV (Key/Value): The most basic. Stores static secrets. Version 1 is a simple key-value store. Version 2 adds versioning, allowing you to track changes and roll back to previous versions of a secret.
    • Enable: vault secrets enable -path=secret kv
    • Write: vault kv put secret/my-app api_key="xyz123"
    • Read: vault kv get secret/my-app
  • Database: As shown above, dynamically generates database credentials for various database systems (PostgreSQL, MySQL, Oracle, etc.). It can create roles, assign permissions, and revoke them automatically.
  • AWS: Generates temporary AWS IAM access keys and secret keys. This is crucial for applications running on AWS that need to interact with AWS services. You configure IAM policies, and Vault issues temporary credentials based on those policies.
    • Enable: vault secrets enable aws
    • Configure: vault write aws/config access_key="..." secret_key="..."
    • Create Role: vault write aws/roles/my-s3-role \ iam_num_users=1 \ iam_user_policies='{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": ["s3:ListBucket", "s3:GetObject"], "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"]}]}'
    • Read Creds: vault read aws/creds/my-s3-role
  • SSH: Generates one-time-use SSH certificates signed by a Vault-managed CA. This allows you to grant temporary SSH access to servers without managing individual public keys on each host.
    • Enable: vault secrets enable ssh
    • Configure CA: vault write ssh/config/ca \ public_key="$(cat ~/.ssh/id_rsa.pub)" \ private_key_format=raw \ private_key="$(cat ~/.ssh/id_rsa)"
    • Generate Cert: vault write ssh-client-signer/sign/my-role \ public_key="$(cat ~/.ssh/id_rsa.pub)" \ ip_filter="10.0.0.0/24,192.168.1.0/24" \ cert_ttl="30m"
  • PKI (Public Key Infrastructure): Acts as a Certificate Authority (CA). It can generate, sign, and revoke X.509 certificates. This is fundamental for securing internal services with TLS.
    • Enable: vault secrets enable pki
    • Configure CA: vault write pki/config/ca \ max_lease_ttl="8760h" \ default_lease_ttl="8760h" \ allow_localhost=true
    • Create Role: vault write pki/roles/my-app-role \ allow_any_name=true \ max_ttl=2160h
    • Generate Cert: vault write pki/issue/my-app-role common_name="myapp.example.com"
  • Identity: Not strictly a secrets engine for storing secrets, but it’s crucial for managing identity and associating policies with entities. It allows you to map external identities (like Kubernetes Service Accounts or LDAP users) to Vault policies.
  • Transit: For cryptographic operations. It doesn’t store secrets directly but allows you to encrypt, decrypt, sign, and verify data using keys managed by Vault. This is useful for encrypting sensitive data before storing it elsewhere or for signing audit logs.
    • Enable: vault secrets enable transit
    • Create Key: vault write transit/keys/my-key-for-encryption
    • Encrypt: vault write transit/encrypt/my-key-for-encryption \ plaintext="SGVsbG8gV29ybGQh" \ context="some_context_for_encryption"
    • Decrypt: vault write transit/decrypt/my-key-for-encryption \ ciphertext="vault:v1:..." \ context="some_context_for_encryption"

The real magic happens when you combine these. For instance, you might use the PKI engine to issue a TLS certificate for a web server, and then use the database engine to provide temporary credentials for that web server to access a backend database.

One aspect often overlooked is how Vault’s secrets engines leverage its lease system. When a dynamic secret is generated, it’s assigned a lease. This lease has a Time-To-Live (TTL) that dictates how long the secret is valid. Vault’s internal scheduler actively monitors these leases and automatically revokes the corresponding secret (e.g., revokes the database user, deletes the IAM key) when the TTL expires. This automatic revocation is the core mechanism for preventing credential sprawl and reducing the attack surface.

The next step is understanding how to integrate these dynamic secrets into your applications using Vault’s various client libraries and agents.

Want structured learning?

Take the full Vault course →