Skip to main content

HashiCorp Vault Secrets Management Guide

Move beyond static credentials with HashiCorp Vault. Configure dynamic database secrets, Kubernetes pod authentication, and automatic secret rotation — so your apps never store long-lived credentials.

✓ Dynamic DB secrets ✓ Kubernetes auth ✓ AppRole setup ✓ Secret rotation

Install Vault (Dev / Production)

# Install via package manager
brew tap hashicorp/tap && brew install hashicorp/tap/vault   # macOS
sudo apt install vault                                        # Ubuntu/Debian

# Start in dev mode (in-memory, auto-unsealed, root token = root)
vault server -dev -dev-root-token-id="root"

# Production: start with config file
vault server -config=/etc/vault/vault.hcl

# /etc/vault/vault.hcl (minimal production config)
# storage "raft" {
#   path    = "/opt/vault/data"
#   node_id = "vault-1"
# }
# listener "tcp" {
#   address     = "0.0.0.0:8200"
#   tls_cert_file = "/etc/vault/tls/vault.crt"
#   tls_key_file  = "/etc/vault/tls/vault.key"
# }
# api_addr = "https://vault.example.com:8200"
# cluster_addr = "https://vault.example.com:8201"
# ui = true

export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='root'
vault status

Dynamic Database Secrets

# Enable the database secrets engine
vault secrets enable database

# Configure PostgreSQL connection
vault write database/config/my-postgres \
  plugin_name=postgresql-database-plugin \
  allowed_roles="app-role" \
  connection_url="postgresql://{{username}}:{{password}}@postgres.example.com:5432/appdb" \
  username="vault-superuser" \
  password="superuser-password"

# Create a role with a creation SQL statement
vault write database/roles/app-role \
  db_name=my-postgres \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

# Generate dynamic credentials (app calls this at startup)
vault read database/creds/app-role

# Response:
# Key                Value
# ---                -----
# lease_id           database/creds/app-role/AbCdEf123456
# lease_duration     1h
# lease_renewable    true
# password           A1a-xxxxxxxxxxxxxxxx
# username           v-root-app-role-yyyyyyyyyyy

Kubernetes Auth Integration

# Enable Kubernetes auth method
vault auth enable kubernetes

# Configure with the cluster's API server
vault write auth/kubernetes/config \
  kubernetes_host="https://kubernetes.default.svc" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
  token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token

# Create a policy for the app
vault policy write app-policy - <<EOF
path "database/creds/app-role" {
  capabilities = ["read"]
}
path "secret/data/app/*" {
  capabilities = ["read"]
}
EOF

# Bind the policy to a Kubernetes service account
vault write auth/kubernetes/role/my-app \
  bound_service_account_names=my-app-sa \
  bound_service_account_namespaces=production \
  policies=app-policy \
  ttl=1h

# In Kubernetes: the app logs in using its mounted SAT
curl -s --request POST \
  --data "{\"jwt\": \"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\", \"role\": \"my-app\"}" \
  $VAULT_ADDR/v1/auth/kubernetes/login | jq '.auth.client_token'

AppRole Authentication

# Enable AppRole auth
vault auth enable approle

# Create AppRole with bound policies
vault write auth/approle/role/ci-pipeline \
  secret_id_ttl=10m \
  token_num_uses=10 \
  token_ttl=20m \
  token_max_ttl=30m \
  secret_id_num_uses=1 \
  policies=deploy-policy

# Get the RoleID (not secret, can be in config)
vault read auth/approle/role/ci-pipeline/role-id
# role_id: 675a50e7-cfe0-be9a-7a5a-c1d19af7b7c9

# Get a SecretID (secret, single-use, short-lived)
vault write -f auth/approle/role/ci-pipeline/secret-id
# secret_id: ed0a642f-2acf-c2da-232f-1b21300d5f29

# Login with RoleID + SecretID
vault write auth/approle/login \
  role_id="675a50e7-cfe0-be9a-7a5a-c1d19af7b7c9" \
  secret_id="ed0a642f-2acf-c2da-232f-1b21300d5f29"

Vault Agent — Auto-Auth Sidecar

# vault-agent-config.hcl
vault {
  address = "https://vault.example.com:8200"
}

auto_auth {
  method "kubernetes" {
    mount_path = "auth/kubernetes"
    config {
      role = "my-app"
    }
  }

  sink "file" {
    config {
      path = "/vault-token"
    }
  }
}

template {
  source      = "/etc/vault-templates/db-config.ctmpl"
  destination = "/app/config/database.yml"
  command     = "kill -HUP $(cat /app/pids/app.pid)"  # reload app on change
}

Frequently Asked Questions

What are dynamic secrets in Vault and why are they better than static secrets?▼

Dynamic secrets are credentials that Vault generates on-demand with a short TTL (time-to-live). Instead of storing a long-lived database password, your application asks Vault for a database credential, Vault creates a new user in your database with the right permissions, returns the credentials, and automatically revokes them when the TTL expires. Benefits: no long-lived credentials to leak, every access is audited, compromised credentials auto-expire, and you can revoke all credentials for a specific lease if you detect a breach. Static secrets (stored passwords) create a single point of failure — one leak means rotating every system that uses that secret.

How does Vault Kubernetes auth work?▼

Vault Kubernetes auth lets pods authenticate to Vault using their Kubernetes Service Account Token (SAT). The flow: (1) Vault is configured with the K8s API server's URL and CA cert. (2) You create a Vault role that maps a Kubernetes service account + namespace to Vault policies. (3) A pod mounts its SAT automatically. (4) The app (or Vault Agent sidecar) sends the SAT to Vault's auth/kubernetes/login endpoint. (5) Vault validates the SAT against the K8s API, confirms the pod's service account matches the role binding, and returns a Vault token. No static credentials ever touch the cluster — authentication is based on the pod's identity.

What is the difference between Vault AppRole and Kubernetes auth?▼

AppRole is a universal auth method designed for machine-to-machine authentication outside of Kubernetes. It uses a RoleID (not secret, shareable) and SecretID (short-lived, single-use) to authenticate. The bootstrap problem: how does an app get the SecretID securely? This requires a trusted delivery mechanism (CI/CD pipeline secrets, separate bootstrap service). Kubernetes auth eliminates the bootstrap problem for K8s workloads by using the cluster's identity system. Use Kubernetes auth for anything running in Kubernetes. Use AppRole for CI/CD pipelines (GitHub Actions, Jenkins), VMs, and non-K8s services.

How do I handle secret rotation in Vault?▼

Vault handles rotation differently by secret type. For dynamic secrets (database, AWS, etc.), rotation is automatic — credentials expire and are regenerated on next request. For static secrets stored in the KV store, use Vault's secret rotation plugins or an external rotation script triggered by a Vault sentinel policy. For the Vault root token and unseal keys, use Vault's rekey operation. For transit secrets (encryption keys), use rotate-key which adds a new key version while keeping the old one for decryption. Most teams also set up Vault Agent with auto-auth on application hosts to cache and renew tokens, so applications never deal with token expiration directly.

Share this tool: X / Twitter LinkedIn
✓ 60,000+ developers use DevPlaybook ★★★★★ 4.8 / 5 on Gumroad ✓ MIT licensed · Instant download ✓ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚡ AI Code Review, Doc Generator & SQL Builder
  • ⚡ All premium templates & early access
  • ⚡ Member discounts on Gumroad products
Start Free Trial →

$9/mo after trial · Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro — $79 →

MIT licensed · Instant download · No subscription

See what's included → Browse all deals →