Skip to content

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 renew 
vault 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
Dynamic secrets are the key advantage of Vault: no secret lives forever. The DB user and AWS keys are automatically revoked when the lease expires — no manual rotation needed.

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
list vs read are separate capabilities. A policy with only 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 unseal 
vault 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