| name | hashicorp-vault |
| description | HashiCorp Vault — secrets management, encryption as a service, and dynamic credentials. Use this skill whenever the user needs to store and retrieve secrets, generate dynamic database credentials, issue short-lived certificates (PKI), set up Kubernetes auth for pod secret access, configure Vault policies, or implement secrets rotation. Trigger for "vault secrets", "vault kv", "vault dynamic credentials", "vault pki", "vault kubernetes auth", "hashicorp vault", or "secrets management vault". |
HashiCorp Vault — Secrets Management
Overview
HashiCorp Vault is a secrets management tool that provides secure storage for tokens, passwords, certificates, and API keys, plus dynamic credential generation — it can create short-lived database credentials on-demand so that no long-lived secrets need to be distributed. Vault supports many backends (AWS, GCP, Azure, databases, PKI, SSH) and authentication methods (Kubernetes, AWS IAM, LDAP, OIDC). The key insight: instead of storing a database password in your app config, Vault generates a new unique credential for each request with a TTL, and the credential is automatically revoked after the lease expires.
When to Use
- Centralizing secret storage across microservices and environments
- Generating dynamic database credentials (Postgres, MySQL, MongoDB)
- Issuing short-lived TLS certificates (PKI secrets engine)
- Kubernetes pod authentication without hardcoded service account tokens
- Encrypting application data at rest without managing encryption keys
- Secret rotation and audit logging for compliance (SOC2, PCI-DSS)
Installation
brew tap hashicorp/tap
brew install hashicorp/tap/vault
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt install vault
vault server -dev &
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='root'
vault status
Key Patterns
KV Secrets Engine — Static Secrets
vault secrets enable -path=secret kv-v2
vault kv put secret/myapp/prod \
database_url="postgres://user:pass@host:5432/db" \
api_key="sk-..."
vault kv get secret/myapp/prod
vault kv get -field=database_url secret/myapp/prod
vault kv list secret/myapp/
vault kv metadata get secret/myapp/prod
vault kv get -version=2 secret/myapp/prod
vault kv delete secret/myapp/prod
vault kv destroy -versions=1 secret/myapp/prod
Dynamic Database Credentials — PostgreSQL
vault secrets enable database
vault write database/config/my-postgres \
plugin_name=postgresql-database-plugin \
allowed_roles="my-app-role" \
connection_url="postgresql://{{username}}:{{password}}@postgres:5432/mydb?sslmode=disable" \
username="vault-admin" \
password="vault-admin-password"
vault write database/roles/my-app-role \
db_name=my-postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"
vault read database/creds/my-app-role
PKI Secrets Engine — TLS Certificate Authority
vault secrets enable -path=pki pki
vault secrets tune -max-lease-ttl=87600h pki
vault write -field=certificate pki/root/generate/internal \
common_name="my-org.com" \
ttl=87600h > CA_cert.crt
vault write pki/config/urls \
issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
crl_distribution_points="$VAULT_ADDR/v1/pki/crl"
vault secrets enable -path=pki_int pki
vault write -format=json pki_int/intermediate/generate/internal \
common_name="my-org.com Intermediate Authority" | jq -r '.data.csr' > pki_intermediate.csr
vault write -format=json pki/root/sign-intermediate \
csr=@pki_intermediate.csr \
format=pem_bundle \
ttl=43800h | jq -r '.data.certificate' > intermediate.cert.pem
vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem
vault write pki_int/roles/my-app \
allowed_domains="my-app.example.com,*.my-app.example.com" \
allow_subdomains=true \
max_ttl="720h"
vault write pki_int/issue/my-app \
common_name="api.my-app.example.com" \
ttl="24h"
Kubernetes Auth — Pod Authentication
vault auth enable kubernetes
vault write auth/kubernetes/config \
kubernetes_host="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_ca_cert="$(cat /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
# my-app-policy.hcl
# Allow the app to read its own secrets
path "secret/data/myapp/prod" {
capabilities = ["read"]
}
# Allow generating dynamic database credentials
path "database/creds/my-app-role" {
capabilities = ["read"]
}
vault policy write my-app-policy my-app-policy.hcl
import hvac, os
client = hvac.Client(url=os.environ["VAULT_ADDR"])
jwt_token = open("/var/run/secrets/kubernetes.io/serviceaccount/token").read()
client.auth.kubernetes.login(role="my-app", jwt=jwt_token)
secret = client.secrets.kv.v2.read_secret_version(path="myapp/prod", mount_point="secret")
db_url = secret["data"]["data"]["database_url"]
Vault Agent — Sidecar for Auto-Auth and Secret Templating
# vault-agent-config.hcl (Kubernetes sidecar)
auto_auth {
method "kubernetes" {
mount_path = "auth/kubernetes"
config = {
role = "my-app"
}
}
sink "file" {
config = {
path = "/vault/token"
}
}
}
template {
source = "/vault/templates/config.tmpl"
destination = "/app/config/config.env"
perms = 0600
command = "kill -HUP $(cat /app/app.pid)" # reload app on secret change
}
{{/* /vault/templates/config.tmpl */}}
{{ with secret "secret/data/myapp/prod" }}
DATABASE_URL={{ .Data.data.database_url }}
API_KEY={{ .Data.data.api_key }}
{{ end }}
{{ with secret "database/creds/my-app-role" }}
DB_USERNAME={{ .Data.username }}
DB_PASSWORD={{ .Data.password }}
{{ end }}
Common Commands
vault status
vault secrets list
vault auth list
vault policy list
vault policy read my-app-policy
vault token lookup
vault token create -policy=my-app-policy -ttl=1h
vault lease renew <lease-id>
vault lease revoke <lease-id>
vault audit list
vault audit enable file file_path=/var/log/vault_audit.log
Pitfalls
- Seal/unseal: Vault starts sealed and must be unsealed with multiple keys (Shamir's Secret Sharing) or auto-unseal (AWS KMS, GCP Cloud KMS) after every restart — plan for auto-unseal in production or Vault restarts cause outages
- Token TTL vs lease TTL: the app token has a TTL, and dynamic credential leases also have TTLs — the Vault Agent handles both renewals automatically; without it, credentials silently expire
- Root token should not be used in production: the root token bootstraps Vault but should be immediately revoked after creating admin tokens with appropriate policies; never commit root tokens to code
- KV v1 vs v2: KV v2 adds versioning and metadata but has a different API path (
/secret/data/<path> vs /secret/<path>) — make sure applications use the correct path
- Audit log overhead: enabling the file audit log on a high-traffic Vault instance writes every request to disk — use a syslog or socket audit device and ship to a centralized logging system to avoid disk saturation
Related Skills
consul — pairs with Vault for service mesh certificate management
nomad — uses Vault for secret injection via template blocks in job specs
opentofu — Vault provider can manage policies, roles, and mounts as code
kubernetes-architect — Vault Agent Injector as a mutating webhook for K8s pods
hashicorp-boundary — uses Vault for brokered credential injection
GitNexus Index
Index path: /Users/localuser/.claude/skills/hashicorp-vault/.gitnexus
Created: 2026-05-24