← Back to Blog
Security May 2026 7 min read

HashiCorp Vault Best Practices: Secrets Management Done Right

Dynamic secrets, auth methods, policy design, and the operational mistakes teams make when scaling Vault in production Kubernetes environments.

Why secrets management is harder than it looks

Most teams start with static secrets in environment variables or config files. It works — until it doesn't. A leaked .env file, a rotated credential that breaks three services, a shared admin password that half the team knows. HashiCorp Vault solves these problems systematically, but only if you use it correctly.

Having deployed and operated Vault across multiple Kubernetes environments, here are the patterns that matter most.

1. Use Dynamic Secrets Wherever Possible

Static secrets are Vault's least powerful feature. Dynamic secrets are where it shines. Instead of storing a database password, Vault generates a unique, time-limited credential on demand — and automatically revokes it when the lease expires.

# Enable the database secrets engine
vault secrets enable database

# Configure a PostgreSQL connection
vault write database/config/my-db \
  plugin_name=postgresql-database-plugin \
  connection_url="postgresql://{{username}}:{{password}}@db:5432/mydb" \
  allowed_roles="app-role"

# Create a role with a short TTL
vault write database/roles/app-role \
  db_name=my-db \
  creation_statements="CREATE ROLE ..." \
  default_ttl="1h" \
  max_ttl="24h"
✓ Dynamic secrets mean a compromised credential is automatically invalid after its TTL. Blast radius of a breach shrinks dramatically.

2. Auth Methods: Choose the Right One

In Kubernetes environments, the Kubernetes auth method is the right choice for workload identity. It lets pods authenticate to Vault using their ServiceAccount JWT token — no static credentials required.

vault auth enable kubernetes

vault write auth/kubernetes/config \
  kubernetes_host="https://kubernetes.default.svc" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

vault write auth/kubernetes/role/my-app \
  bound_service_account_names=my-app-sa \
  bound_service_account_namespaces=production \
  policies=my-app-policy \
  ttl=1h

For human operators, prefer OIDC auth tied to your identity provider (Okta, Azure AD, Google Workspace). Avoid userpass auth in production — it's a static credential anti-pattern.

3. Policy Design: Least Privilege

Vault policies should be narrow and explicit. The biggest mistake I see is teams writing overly broad policies because it's easier than being precise.

# Bad: too broad
path "secret/*" {
  capabilities = ["read", "list", "create", "update", "delete"]
}

# Good: scoped to what the app actually needs
path "secret/data/myapp/{{identity.entity.name}}/*" {
  capabilities = ["read"]
}

path "database/creds/myapp-role" {
  capabilities = ["read"]
}
✓ Use templated policies with identity.entity.name or identity.groups.names to avoid creating one policy per service. It scales much better.

4. Vault Agent for Kubernetes Workloads

Vault Agent Injector is the cleanest way to deliver secrets to Kubernetes pods. It injects a sidecar that authenticates to Vault, fetches secrets, and writes them as files or environment variables — without your application code ever touching Vault directly.

annotations:
  vault.hashicorp.com/agent-inject: "true"
  vault.hashicorp.com/role: "my-app"
  vault.hashicorp.com/agent-inject-secret-config: "secret/data/myapp/config"
  vault.hashicorp.com/agent-inject-template-config: |
    {{- with secret "secret/data/myapp/config" -}}
    DB_PASSWORD={{ .Data.data.db_password }}
    API_KEY={{ .Data.data.api_key }}
    {{- end }}

5. Operational Best Practices

Auto-unseal

Manual unseal using operator keys is a single-point-of-failure in production. Use cloud auto-unseal — AWS KMS, Azure Key Vault, or GCP Cloud KMS — so Vault automatically unseals after a restart without human intervention.

Audit logging

Enable audit devices from day one. Every request to Vault is logged, including the token used, the path accessed, and the response code. This is invaluable for incident response and compliance.

vault audit enable file file_path=/var/log/vault/audit.log

Lease management

Monitor and manage leases actively. Leaked leases consume Vault resources and can hit limits. Set aggressive TTLs and implement lease renewal in your applications rather than relying on max TTL.

Common Mistakes to Avoid

🚫 Root token in CI/CD. Create purpose-specific tokens with narrow policies. The root token should only be used for initial setup and then revoked.
🚫 Not testing Vault HA failover. Deploy Vault in HA mode (Raft integrated storage or Consul backend) and regularly test failover. Discovering HA doesn't work during an incident is a bad time.
🚫 Ignoring secret versioning. Use KV v2 (not v1) for static secrets. v2 provides versioning, soft deletion, and a check-and-set operation that prevents accidental overwrites.

Final thoughts

Vault is one of those tools where the distance between "using it" and "using it well" is significant. The patterns above — dynamic secrets, appropriate auth methods, least-privilege policies, and Vault Agent for Kubernetes — cover the majority of what a production Vault deployment needs.

If you're starting fresh, begin with the Kubernetes auth method and KV v2. Add dynamic secrets as you identify static credentials in your stack. Build audit logging from day one. The incremental approach works well here.