Vault Runbook & Cheatsheet
Vault Runbook & Cheatsheet
Vault is identity-based secrets management: it stores secrets encrypted, hands them out against policy, issues short-lived dynamic credentials, and encrypts data as a service. Part one stands up a server and works through init, unseal, secrets, policies, and auth; part two is the CLI and concept reference.
Concept
Vault holds an encrypted store behind a seal. It starts sealed; you unseal it, authenticate to get a token, and every request is checked against a policy.
| Piece | Role |
|---|---|
| seal / unseal | The master key is split (Shamir) or held by a KMS; Vault is useless until unsealed. |
| auth method | How a human or machine proves identity and gets a token (token, userpass, AppRole, OIDC, k8s). |
| token | What every request carries; scoped by attached policies, with a TTL. |
| policy | Path-based allow rules (deny by default) that gate every operation. |
| secrets engine | Mounted at a path; stores static secrets (KV) or mints dynamic ones (db, PKI, cloud). |
Why dynamic beats static Vault’s real value is short-lived, on-demand credentials (a database login that exists for an hour, then is revoked) rather than long-lived secrets copied into config files.
Install
# Debian / Ubuntu 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-get update && sudo apt-get install -y vault vault version # OpenBao: download the 'bao' binary from the OpenBao releases # page; every command below then uses 'bao' in place of 'vault'.
Run a server
Dev mode to learn; a real config file with integrated Raft storage for anything you keep.
# In-memory, auto-unsealed, root token printed to the screen vault server -dev # In another shell, point the CLI at it export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='' vault status
Never in production Dev mode keeps everything in memory, unsealed, with a known root token. It is for experiments only — it loses all data on exit.
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-1.internal:8200"
cluster_addr = "https://vault-1.internal:8201"
ui = trueIntegrated storage Raft is the standard backend — no external database, data lives on disk and replicates across the cluster. Always run with TLS; run Vault as a dedicated non-root user via systemd.
Initialize & unseal
Initialization happens exactly once per cluster. It returns the unseal key shares and the initial root token — the most sensitive output Vault ever produces.
vault operator init -key-shares=5 -key-threshold=3 # Prints 5 unseal keys and one root token. Distribute the # key shares to different trusted holders; store none together.
# Provide 'threshold' different key shares (3 of 5 here) vault operator unseal # paste key 1 vault operator unseal # paste key 2 vault operator unseal # paste key 3 -> Sealed: false vault login # paste the root token
Auto-unseal in production Manual unseal on every restart does not scale. Configure a seal stanza backed by a cloud KMS or HSM so the node unseals itself; keep the Shamir recovery keys offline for break-glass.
Store & read KV secrets
# Mount the versioned key-value engine at secret/ vault secrets enable -path=secret kv-v2 # Write and read a secret vault kv put secret/app/db username=svc password=s3cr3t vault kv get secret/app/db vault kv get -field=password secret/app/db # Versioning: history, a specific version, undelete vault kv get -version=2 secret/app/db vault kv metadata get secret/app/db
KV v1 vs v2 v2 keeps version history and soft-deletes; its API path inserts data/ (so a policy for secret/app/db is written as secret/data/app/db). That path difference trips up almost everyone once.
Policies
Policies are deny-by-default, path-based capability grants. Nothing is allowed until a policy says so.
# app-policy.hcl - read-only on one KV v2 branch
path "secret/data/app/*" {
capabilities = ["read"]
}
path "secret/metadata/app/*" {
capabilities = ["list", "read"]
}vault policy write app app-policy.hcl vault policy read app vault policy list
Capabilities create, read, update, delete, list, sudo, deny. Grant the narrowest set on the narrowest path; an explicit deny always wins over any allow.
Auth methods
Root tokens are for setup only. Machines authenticate with AppRole (a role id + a secret id); humans use OIDC/userpass. Tokens come out scoped to the role’s policies.
vault auth enable approle # Bind the 'app' policy to a role vault write auth/approle/role/app \ token_policies="app" token_ttl=1h token_max_ttl=4h # Fetch the two credentials the app will use vault read auth/approle/role/app/role-id vault write -f auth/approle/role/app/secret-id # The app logs in with them to get a scoped token vault write auth/approle/login role_id=... secret_id=...
Stop using the root token Revoke or seal away the initial root token after setup (vault token revoke). Day-to-day access should always come through an auth method with a scoped policy.
Dynamic secrets
The payoff: Vault generates a credential on request, hands it out with a lease, and revokes it automatically when the lease ends.
vault secrets enable database # Teach Vault how to reach the DB (admin creds used only to mint users) vault write database/config/appdb \ plugin_name=postgresql-database-plugin \ connection_url="postgresql://{{username}}:{{password}}@db:5432/app" \ allowed_roles="reader" username="vault-admin" password="..." # A role that mints a short-lived, least-privilege login vault write database/roles/reader \ db_name=appdb default_ttl=1h max_ttl=24h \ creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" # Get a fresh credential - auto-revoked when the lease ends vault read database/creds/reader
Leases & revocation Every dynamic secret has a lease you can renew or revoke early (vault lease revoke). Other engines follow the same shape: PKI issues short-lived certs, transit encrypts data without ever revealing keys.
Operate
# Turn on an audit device (do this before real secrets land) vault audit enable file file_path=/var/log/vault/audit.log # Raft snapshot for backup (use a scoped token, not root) vault operator raft snapshot save vault-$(date +%F).snap # Rotate the unseal keys / root token when a holder changes vault operator rekey -init -key-shares=5 -key-threshold=3 vault operator generate-root -init
Audit first Enable an audit device early — it records every request (with secret values HMAC’d). If all audit devices are down, Vault blocks requests by design, so run at least two.
Command line
| Command | Does |
|---|---|
| vault status | Seal state, version, HA mode. |
| vault operator init / unseal | One-time init; unseal a sealed node. |
| vault login / token revoke | Authenticate; revoke a token. |
| vault kv put / get / delete | Write / read / delete KV secrets. |
| vault kv metadata / undelete | Version history and recovery (v2). |
| vault secrets enable / list | Mount / list secrets engines. |
| vault auth enable / list | Mount / list auth methods. |
| vault policy write / read / list | Manage ACL policies. |
| vault read / write / list | Raw path operations (any engine). |
| vault lease renew / revoke | Manage dynamic-secret leases. |
| vault operator raft snapshot | Back up / restore integrated storage. |
Environment VAULT_ADDR points the CLI at the server; VAULT_TOKEN carries your token. Both are read by every command.
KV v2 paths
| CLI path | API path (for policies) |
|---|---|
| secret/app/db | secret/data/app/db |
| kv metadata secret/app | secret/metadata/app |
| kv delete secret/app/db | secret/data/app/db (soft delete) |
| kv destroy | secret/destroy/app/db (permanent) |
The v2 gotcha The friendly kv commands hide the data/ and metadata/ segments, but policies must spell them out.
Auth methods
| Method | For |
|---|---|
| token | Built-in; the raw token primitive. |
| userpass | Simple username/password for humans. |
| approle | Machines / apps (role id + secret id). |
| oidc / jwt | SSO for humans via an identity provider. |
| kubernetes | Pods authenticate with their service-account token. |
| aws / azure / gcp | Cloud instances authenticate by their identity. |
| ldap | Directory-backed human auth. |
Secrets engines
| Engine | Provides |
|---|---|
| kv (v1 / v2) | Static secrets; v2 adds versioning. |
| database | Dynamic DB credentials (Postgres, MySQL, and more). |
| pki | On-demand short-lived TLS certificates. |
| transit | Encryption as a service; keys never leave Vault. |
| aws / azure / gcp | Dynamic cloud IAM credentials. |
| ssh | Signed SSH certs / one-time passwords. |
| totp | Generate / validate TOTP codes. |
Policy capabilities
| Capability | Allows |
|---|---|
| read | Read a path. |
| create / update | Write new / change existing. |
| delete | Remove. |
| list | Enumerate keys under a path. |
| sudo | Access root-protected paths. |
| deny | Explicitly forbid — overrides any allow. |
Matching Exact paths, a * suffix wildcard, or + single-segment wildcards. Most specific match wins; deny always beats allow.
Harden
| Area | Lever |
|---|---|
| Root token | Use only for initial setup, then revoke it; regenerate on demand when truly needed. |
| Unseal keys | Distribute shares to separate holders; store none together; auto-unseal via KMS/HSM with offline recovery keys. |
| TLS | Always on; never run a listener without it outside dev. |
| Least privilege | Narrow policies on narrow paths; deny by default; scope token TTLs tightly. |
| Dynamic over static | Prefer short-lived generated credentials to long-lived stored ones. |
| Audit | Enable at least two audit devices before real secrets; ship the log off-host (see the Splunk / ES sheets). |
| Backups | Regular Raft snapshots with a snapshot-scoped token, stored encrypted off the cluster. |
| Least surface | Run as a non-root user, firewall 8200/8201, disable the UI if unused. |
References
| Resource | Use | Link |
|---|---|---|
| Vault docs | Concepts, engines, auth, API | developer.hashicorp.com/vault |
| Raft deploy guide | Production single-cluster install | day-one-raft guide |
| OpenBao | The MPL 2.0 fork (bao CLI) | openbao.org |