HashiCorp Vault Reference: Dynamic Secrets, Auth Methods, Policies, K8s Agent Injector
HashiCorp Vault is the standard for secrets management — dynamic secrets, PKI, encryption as a service, and fine-grained access policies. This covers day-to-day operations and common integration patterns.
1. Vault Basics & CLI
vault CLI — auth, read/write, namespaces
# Login: vault login # interactive (browser/token prompt) vault login -method=userpass username=admin vault login -method=aws # AWS IAM auth vault login -method=kubernetes role=my-role # K8s service account auth export VAULT_ADDR="https://vault.example.com:8200" export VAULT_TOKEN="hvs.XXXXXXXXXX" # or use VAULT_ROLE_ID/VAULT_SECRET_ID vault status # check seal state + cluster info vault token lookup # what am I? what policies do I have? # Read/write/delete secrets: vault kv put secret/myapp/config db_password="secret123" api_key="abc" vault kv get secret/myapp/config # read current version vault kv get -field=db_password secret/myapp/config # single field (for scripts) vault kv get -format=json secret/myapp/config | jq '.data.data' vault kv delete secret/myapp/config # soft delete (versioned) vault kv undelete -versions=1 secret/myapp/config # restore # List secrets: vault kv list secret/ # list top-level keys vault kv list secret/myapp/ # list keys under path
2. KV Secrets Engine
KV v2 — versioning, metadata, soft deletes
# Enable KV v2: vault secrets enable -path=secret kv-v2 # Or mount at a different path: vault secrets enable -path=apps -version=2 kv # KV v2 always stores previous versions: vault kv put apps/myservice db_pass=v1 vault kv put apps/myservice db_pass=v2 vault kv get apps/myservice # returns v2 vault kv get -version=1 apps/myservice # get v1 vault kv metadata get apps/myservice # all versions + timestamps vault kv metadata put -max-versions=10 apps/myservice # keep 10 versions vault kv metadata put -delete-version-after=720h apps/myservice # auto-expire # Compare KV v1 vs v2: # v1: simple key/value, no versioning, no soft-delete # v2: versioning, check-and-set, soft delete + undelete, metadata # Secret leases (for TTL-aware consumption): vault lease renewvault lease revoke
3. Dynamic Secrets
Database, AWS, and PKI — credentials that expire automatically
# Database secrets engine — generates ephemeral credentials:
vault secrets enable database
vault write database/config/my-postgresql \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@db:5432/mydb?sslmode=disable" \
allowed_roles="my-role" \
username="vault-admin" \
password="vault-admin-password"
vault write database/roles/my-role \
db_name=my-postgresql \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"
# Use it — get a fresh DB credential:
vault read database/creds/my-role
# Key Value
# username v-root-my-role-xxxx (auto-generated, expires in 1h)
# password A1a-randompassword
# AWS secrets engine — dynamic IAM access keys:
vault secrets enable aws
vault write aws/roles/s3-reader \
credential_type=iam_user \
policy_document=@s3-read-policy.json
vault read aws/creds/s3-reader # returns AWS access key + secret that expire
# PKI secrets engine — dynamic TLS certificates:
vault secrets enable pki
vault write pki/root/generate/internal \
common_name=example.com ttl=87600h
vault write pki/roles/my-role \
allowed_domains=example.com allow_subdomains=true max_ttl=72h
vault write pki/issue/my-role common_name=myservice.example.com
# Returns certificate + private key — valid for 72h, auto-expires
4. Auth Methods
Kubernetes, AppRole, AWS IAM — how services authenticate
# Kubernetes auth (best for K8s workloads — no secrets needed):
vault auth enable kubernetes
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc" \
token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
vault write auth/kubernetes/role/my-app \
bound_service_account_names=my-service-account \
bound_service_account_namespaces=production \
policies=my-app-policy \
ttl=1h
# In-pod authentication (agent sidecar pattern — most common):
# vault-agent-injector handles this automatically via annotations:
# vault.hashicorp.com/agent-inject: "true"
# vault.hashicorp.com/role: "my-app"
# vault.hashicorp.com/agent-inject-secret-config: "secret/myapp/config"
# AppRole (for CI/CD, non-K8s services):
vault auth enable approle
vault write auth/approle/role/my-ci \
secret_id_ttl=10m \
token_num_uses=10 \
token_ttl=20m \
token_max_ttl=30m \
secret_id_num_uses=40 \
policies=ci-policy
vault read auth/approle/role/my-ci/role-id # static, embed in app config
vault write -f auth/approle/role/my-ci/secret-id # generate new secret ID (short-lived)
# Login with AppRole:
vault write auth/approle/login role_id= secret_id=
# AWS IAM auth (for EC2/Lambda/ECS — no stored credentials):
vault auth enable aws
vault write auth/aws/role/my-ec2 \
auth_type=iam \
bound_iam_principal_arn=arn:aws:iam::123456789:role/my-ec2-role \
policies=my-policy ttl=1h
5. Policies
HCL policy syntax — capabilities and path patterns
# Vault policy = list of path + capabilities # Capabilities: create read update delete list sudo deny # Write a policy: vault policy write my-app-policy - <vault kv get secret/myapp/config
read on secret/data/myapp/* can’t list keys under secret/metadata/myapp/ — you must add a separate path for metadata with list.6. Vault Agent & Kubernetes Sidecar
Auto-inject secrets into pods without app code changes
# Vault Agent Injector — annotate pods, Vault handles auth + secret delivery
# Install:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault \
--set "injector.enabled=true" \
--set "server.dev.enabled=false"
# Annotate your Deployment:
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "my-app"
# Inject as file at /vault/secrets/db-creds:
vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/my-role"
# Custom template (extract just the password):
vault.hashicorp.com/agent-inject-template-db-creds: |
{{- with secret "database/creds/my-role" -}}
export DB_PASSWORD="{{ .Data.password }}"
export DB_USERNAME="{{ .Data.username }}"
{{- end }}
vault.hashicorp.com/agent-init-first: "true" # block until secrets injected
# In app: source /vault/secrets/db-creds
# Or: read /vault/secrets/db-creds as file
# Vault Agent config (without K8s — for VMs):
auto_auth {
method "aws" { config { role = "my-app" } }
}
template {
destination = "/etc/myapp/secrets.env"
contents = <
7. Operations: Seal, Unseal, HA
Production Vault operations — init, unseal, raft cluster
# Initialize (one-time, generates unseal keys + root token): vault operator init -key-shares=5 -key-threshold=3 # Produces 5 unseal keys — need any 3 to unseal # Store keys separately (different people/locations)! # Unseal: vault operator unsealvault operator unseal vault operator unseal # after 3 keys, Vault is unsealed # Auto-unseal (production — avoids manual unseal after restart): # Use AWS KMS, GCP KMS, or Azure Key Vault as the unseal key source seal "awskms" { region = "us-east-1" kms_key_id = "arn:aws:kms:us-east-1:123:key/xxx" } # Raft HA (built-in, recommended over Consul backend): vault operator raft list-peers # show cluster members vault operator raft join https://vault-1:8200 # join cluster vault status # leader/follower status # Snapshot (backup): vault operator raft snapshot save /tmp/vault-backup.snap vault operator raft snapshot restore /tmp/vault-backup.snap # restore # Rotate root token (after setup): vault token revoke # ONLY after creating admin tokens! # Or: vault operator generate-root to generate a new root if needed
Track HashiCorp Vault, Terraform, and other infrastructure tool releases.
ReleaseRun monitors releases for Kubernetes, Docker, and 13+ DevOps technologies.
Related: Kubernetes RBAC Reference | ArgoCD & GitOps Reference | Terraform Reference
🔍 Free tool: HTTP Security Headers Analyzer — if Vault is behind a web proxy, check that it's returning the right HTTP security headers.
Founded
2023 in London, UK
Contact
hello@releaserun.com