T Techclick ← Vault hub
HashiCorp Vault · Secrets factory · Interactive lesson

Vault is a secrets factory. Unseal, auth, policy, then the lease.

The ticket says “Vault is down — pipeline 403.” You run vault status and the lab cluster is Sealed=false, HA Mode: active. Students reseal. Operators walk the factory: is the floor powered, did auth print a token, does the policy name this path, and is the lease still alive? This lesson is the official line — unseal/HA → auth → policy → lease — and the proof fields that close the ticket.

20 min read · L2 primary · Quiz at end · Dummy lab only · Pair: Evidence desk

⚡ Quick Answer

Vault is a secrets factory: unseal/HA → auth → policy → lease. The token is the session. Prove it with vault status, token lookup, policy path, and lease expire_time.

After this page you can

Quick answer

Vault is a secrets factory. While a node is sealed, official docs allow only unseal and status. After unseal, one HA node is active; standbys forward or return 307. Auth verifies identity and prints a token — official wording: conceptually a session ID — with policies attached at login. Those policies are deny by default and match API paths plus capabilities. Every dynamic secret and every service token carries a lease (TTL, renew, revoke). KV stores a value and does not issue a lease. Success is a named token + a matching ACL + a live expire_time — not a green seal tile.

Say this out loud

I do not start with Shamir keys. I ask whether the node I hit is unsealed and active, whether auth issued a token, which policy path that token carries, and whether the lease is still inside TTL. Unsealed is necessary. It is not a secret.

1. Why unsealed is not a secret

Every other blog starts with “Vault is a secrets engine.” That is why students freeze at 02:10. The real object is the leased ticket. Unseal, HA, auth and policy are stations the factory walks before it prints that ticket — or refuses to.

Official seal concept: a Vault server starts sealed. It can reach storage, but it cannot decrypt. Unsealing reconstructs the plaintext root key so Vault can unwrap the encryption keyring. Until that happens, the only legal operations are unseal and status. Exit code 0 = unsealed. Exit code 2 = sealed. That is all Sealed=false promised.

Authorization is a later station. Official authentication concept: before a client can interact, it authenticates against an auth method. Vault generates a token. The token is conceptually similar to a session ID on a website. Policies attach at that moment. A perfect unseal plus a token whose policy says secret/data/finance/* read will still 403 a write, an hr/ prefix, or a KV v1-shaped HTTP call on a v2 mount.

Hero · the factory floor
Teaches: a CI request becomes a leased secret ticket that walks unseal, HA, auth and policy before it reaches the secret
Notice: Vault does not “hand out a secret.” It tries to manufacture a leased ticket and stamp it. The cube can be open and the request still dies at the policy gate.

What the ticket asked

“Vault is down — pipeline 403.” That sentence is a hypothesis. The factory may already be unsealed and printing a deny.

What you prove first

Identity of the node, then Sealed + HA Mode, then the failing token, then the ACL path, then the lease. The evidence desk is the night-shift version of this order.

The lie every L1 repeats

“Sealed is false, so Vault is fine — we need a wider policy.” An unsealed active node only means the factory can decrypt and answer. If the token is dead, the ACL is read-only, or the database lease expired, widening the policy just prints more 403s — or worse, a secret/* grant you will own at the next audit.

Dummy lab · vault status (not a customer cluster)
vault-lab $ vault status
Key                     Value
---                     -----
Seal Type               shamir
Initialized             true
Sealed                  false
Total Shares            5
Threshold               3
Version                 1.17.2
Storage Type            raft
Cluster Name            vault-lab
HA Enabled              true
HA Mode                 active
Active Since            2026-08-15T10:42:18Z
Raft Committed Index    18422

What you say: Unsealed, and this node is active. Official status fields: Sealed false means ready to operate; HA Mode active means this process holds the lock. Next command is not another unseal. Next command is the token, the policy, then the lease.

2. Mental model — four stations on one ticket

Hold four parts. Interviews fail when people mix them. Official architecture: after authentication, the auth method supplies policies, the token store issues a client token, that token may carry a lease, and later requests present the token so Vault loads the policies.

1. Unseal / HA is the floor

Shamir threshold or auto-unseal via KMS/HSM. Each Shamir node unseals itself — shares are not cluster-gossiped. One node grabs the HA lock and becomes active; the rest are standby and forward or 307. Necessary. Not a grant.

2. Auth prints the session

Mount path such as approle/, kubernetes/, ldap/, token/. Official: the generated token is conceptually a session ID. Name the mount, the role, token_ttl, secret_id_ttl. A missing mount is not a seal problem.

3. Policy is the door list

HCL path "…" { capabilities = […] }. Deny by default. Capabilities: create, read, update, patch, delete, list, sudo, deny. deny always wins. The path string must match the API, not the CLI convenience path.

4. The lease is the ticket

Official: every dynamic secret and every service token gets a lease — TTL, renewability, revoke. When the lease expires, Vault revokes the data. When you revoke a token, Vault revokes every lease that token created. KV does not issue leases.

Visual · four stamps on one ticket
Teaches: unseal/HA, auth, policy and lease are four stations on one secret ticket
Notice: you do not buy four products. One request walks four stations. Stop at the first red gate.
Flow 1 · one ticket, four stations, one lease
Request 18422 · one token, one policy set, one lease 1 Unseal / HA Sealed=false HA Mode active 2 Auth token = session ID approle/ · 20m 3 Policy path + capability finance-read 4 Lease ttl · renew · revoke expire_time Service token hvs.* · renewable · child tree Dynamic secret lease_id always returned KV v2 no lease · /data/ + version Auth maps identity → policies → token. Policy evaluates the API path. Lease is what you renew or revoke. Revoke the token and Vault revokes every lease that token created. KV version pins are not leases. Source: Seal/Unseal · HA · Authentication · Policies · Lease, renew, and revoke

Read left → right. Station 1 is power. Station 2 prints the session. Station 3 names the door. Station 4 is the ticket that dies on a clock.

Unseal answers “can this process decrypt storage?” Official: Vault encrypts data with an encryption key, wraps that key with a root key, and wraps the root key with the unseal key (Shamir shares or an auto-unseal device). Auto-unseal recovery keys cannot decrypt the root key. If the KMS key is gone, the cluster is gone — even from backups.

Auth answers “who is on the wire, and which policies attach?” Official: enable an auth method at a path; login is not required to use the same path name as the type. AppRole is for machines: role_id plus secret_id (unless bind_secret_id is off). The login returns client_token, token_duration, token_policies.

Policy answers “may this token do this verb on this API path?” Official: empty policy grants nothing. Most-specific match wins; deny always wins. Generating database credentials is HTTP GET, so the capability is read, not create. On KV v2 the payload lives under …/data/… and list lives under …/metadata/….

Lease answers “how long is this data still valid, and can I extend it?” Official: dynamic secrets always return a lease_id. Renew increment is from now, not from the old expiry, and the backend may ignore your increment — read the new TTL. Prefix revoke (vault lease revoke -prefix database/) is the incident move. The UI lists leases under the Access tab.

3. Factory path — unseal/HA → auth → policy → lease

The first request of a new identity has no token yet. It walks the factory. Later requests of the same token skip login and ride the token lease until TTL. That is why “I fixed the policy” sometimes does nothing until the old token dies — and why a 20-minute token_ttl on a 30-minute pipeline is a design bug, not an outage.

Path · first login vs later renew
Teaches: a sealed diamond splits unseal work from the auth-policy-lease path operators prove on a live lease
Notice: the diamond is not allow/deny. It is “is this node sealed?” Juniors stare at Sealed=false. Seniors stare at token policies and expire_time.
Flow 2 · official factory order (student labels)
Caller VAULT_ADDR → status → setup or reuse 1 Ingress API / UI :8200 Sealed? status no SETUP — print a new ticket no usable token yet Yes → unseal only unseal+status HA Mode active / standby Auth login role_id + secret_id Map policies attach to token Issue token token store ACL + lease path then TTL REUSE — later requests of the same token present X-Vault-Token · skip login · evaluate ACL · renew lease or re-auth when TTL is gone Official facts students invert 1. Sealed nodes cannot serve secrets. Only unseal and status work. Exit 2 = sealed. 2. Standbys forward by default (since 0.6.2) or 307 to api_addr. HA does not add read scale. 3. A second login issues a new token. It does not revoke the first one. 4. Policy capability follows the HTTP verb. database/creds/role is GET → read. 5. KV does not issue leases. A lease_duration on some KV responses is not a renewable ticket. Source: Seal/Unseal · status · HA · Authentication · Policies · Lease, renew, and revoke · KV secrets engine

Read left → right, then the green reuse bar. Decision diamond = “is this node sealed?” Do not jump from a 403 to Shamir keys while Sealed=false.

#1 student trap — AppRole 403 on an unsealed cluster

The first packets of a CI job are a login, then a read. Official AppRole: role_id is always required; secret_id is required when bind_secret_id is true (the default). secret_id_ttl=24h and token_ttl=20m look like “Vault is down” at 02:10. Lookup the failing token. If lookup itself 403s, the session is already dead — re-auth, do not reseal.

4. How to choose the next station

You are not choosing a product. You are choosing which factory station actually failed. Same 403, five different next commands.

ChoiceUse whenDo not use whenProof you were right
Unseal (Shamir / auto-unseal) Sealed=true on the node the job hits. Quote Unseal Progress / recovery vs unseal keys. The same address already shows Sealed=false. That is malpractice. vault status exit 0; Sealed=false.
Talk to the active / VIP Writes fail or 307; this node shows HA Mode: standby. Or request forwarding is off. You unseal a follower that is already unsealed. Followers still need a leader. HA Mode: active on the address in VAULT_ADDR, or a working VIP + api_addr.
Fix / re-issue auth vault auth list missing approle/, role TTL expired, or token lookup fails. You mint a root token into CI “until morning.” Official: root is emergency-only and revoked after setup. Login returns token_policies including the intended name; lookup shows remaining ttl.
Fix the ACL path Token works on secret/data/finance/*, fails on hr/* or on a write. Or CLI works and raw HTTP 404s without /data/. You rewrite the ACL to secret/* in an incident. Least privilege was working. vault policy read shows the API path + the verb you actually send.
Renew or replace the lease Dynamic DB/AWS creds worked an hour ago. Cluster still unsealed. You treat a KV version pin as a lease, or you “roll back” by destroying the current KV version without a ticket. vault lease lookup quotes expire_time + ttl + renewable.
Enterprise namespace Token minted in admin/, secret lives in payments/. Same path string, different tree. You paste the ACL into root and assume children inherit payload access. Speak VAULT_NAMESPACE / X-Vault-Namespace out loud, then retry login in that tree.

Official HA does not increase read scale — the bottleneck is the storage lock. Official lease increment is advisory. Official policy * glob is only valid as the last character of the path. Those three sentences save a Friday night.

5. Runbook Side A → B → C

Lab values only. Cluster vault-lab, UI https://vault-lab.example.com:8200/ui, raft node-1 10.0.7.11 leader, node-2 10.0.7.12, node-3 10.0.7.13, role app-finance, policy finance-read, KV secret/finance/db version 7, database role finance-ro. Nothing here is a live tenant. Do not paste a real token, unseal share, or secret_id into a ticket.

Side A — unseal, HA, and the auth door (building the factory floor)

Primary source: Seal/Unseal + status + High availability mode + AppRole.

  1. Prove the node the job actually hits

    On the caller’s VAULT_ADDR, run vault status. Quote Sealed, HA Enabled, HA Mode, Storage Type, Version. Official: this command prints even when sealed. If Sealed=true, stop — only unseal and status work. Shamir: enter shares until Threshold. Auto-unseal: check the KMS/HSM, not Slack for Shamir keys.

  2. Name the active desk

    Lab: node-1 HA Mode: active, node-2/3 standby. Official: the active advertises api_addr (or VAULT_API_ADDR). Standbys forward by default; clients can force 307 with X-Vault-No-Request-Forwarding. Writes that pin a standby address without forwarding fail in the client. Point at the HA VIP.

  3. Name the auth mount, not the product slogan

    Run vault auth list. Official columns: Path, Type, Description. Lab must show approle/. Enable-at-a-path: vault auth enable -path=approle approle. A missing mount explains a CI login failure before any policy is involved.

  4. Read the role the pipeline uses

    Lab role app-finance. Fields that matter: token policies, token_ttl, token_max_ttl, secret_id_ttl, bind_secret_id. Official AppRole recommends token_type=batch for machines. Batch tokens are not renewable — the app must re-login. That is a design choice, not an outage.

Dummy lab · status + auth + role
vault-lab $ vault status
Sealed                  false
HA Enabled              true
HA Mode                 active
Storage Type            raft

vault-lab $ vault operator raft list-peers
Node      Address            State     Voter
node-1    10.0.7.11:8201     leader    true
node-2    10.0.7.12:8201     follower  true
node-3    10.0.7.13:8201     follower  true

vault-lab $ vault auth list
Path           Type        Description
approle/       approle     n/a
kubernetes/    kubernetes  n/a
token/         token       token based credentials

vault-lab $ vault read auth/approle/role/app-finance
key                 value
role_name           app-finance
token_policies      [default finance-read]
token_ttl           20m
token_max_ttl       30m
secret_id_ttl       24h
bind_secret_id      true

Side B — policy and the API path (printing the ticket, choosing stamps)

Primary source: Policies + KV v2.

  1. Lookup the token you are actually using

    Never assume the operator token is the CI token. vault token lookup on the failing credential. Quote policies, path (the login path), ttl, renewable, type. Official prefixes since 1.10: service hvs., batch hvb., recovery hvr.. A batch token cannot be renewed — the app must log in again.

  2. Read the ACL, not the ticket summary

    Lab policy finance-read is read on secret/data/finance/*, list on secret/metadata/finance/*, and read on database/creds/finance-ro. A write, an hr/ prefix, or database/creds/hr-ro 403s on purpose. That is the control.

  3. Put /data/ in the policy if the mount is KV v2

    The CLI convenience path is secret/finance/db. The ACL and the HTTP API use /v1/secret/data/finance/db. List needs /metadata/. This is the most common “policy looks right, API 403s” bug. Do not grant the CLI path and call it done.

  4. Name the namespace before you compare paths

    If the org uses Enterprise namespaces, a token minted in admin/ does not inherit payments/ secrets. Same path string, different tree. Set VAULT_NAMESPACE or the X-Vault-Namespace header, then login again inside that namespace.

Dummy lab · token lookup + policy (not a customer token)
vault-lab $ vault token lookup
Key                 Value
---                 -----
accessor            3c29bc22-lab-accessor
creation_ttl        20m
display_name        approle
expire_time         2026-08-15T11:02:18Z
id                  hvs.CAESIlabdummy0001
path                auth/approle/login
policies            [default finance-read]
renewable           true
ttl                 18m
type                service

vault-lab $ vault policy read finance-read
path "secret/data/finance/*" { capabilities = ["read"] }
path "secret/metadata/finance/*" { capabilities = ["list"] }
path "database/creds/finance-ro" { capabilities = ["read"] }

Side C — prove the lease (the ticket that expires)

Primary source: Lease, renew, and revoke + lease command.

  1. Read with the same token the app uses

    Lab: vault kv get secret/finance/db returns username=finance_ro, version=7. If the app expects version 6, that is a pin, not a seal. Official: KV does not issue a lease even if some responses show a duration field.

  2. Issue (or look up) the dynamic lease

    Lab: vault read database/creds/finance-ro returns username, password, and a lease_id such as database/creds/finance-ro/hvle-lab0001. Then vault lease lookup that id. Quote expire_time, ttl, renewable. Official: increment is from now; inspect the new TTL; the backend may ignore your request.

  3. Know what revoke actually does

    Official: revoke the lease and the secret is invalid immediately (AWS keys deleted at the provider). Revoke the token and Vault revokes every lease that token created. Prefix revoke (vault lease revoke -prefix database/) is how you contain a stolen role. UI path: Access → Leases.

  4. Confirm an audit device exists before you promise forensics

    vault audit list must show a device (lab: file//var/log/vault_audit.log). Official: auditing starts disabled. No device = you cannot prove who read payroll. Enabling one now only helps the next incident. Night-shift write-up: evidence desk.

Dummy lab · dynamic lease lookup (not customer credentials)
vault-lab $ vault read database/creds/finance-ro
Key                Value
---                -----
lease_id           database/creds/finance-ro/hvle-lab0001
lease_duration     1h
lease_renewable    true
username           v-approle-finance-ro-lab
password           s3cret-lab-only

vault-lab $ vault lease lookup database/creds/finance-ro/hvle-lab0001
id            database/creds/finance-ro/hvle-lab0001
issue_time    2026-08-15T10:44:00Z
expire_time   2026-08-15T11:44:00Z
last_renewal  (never)
renewable     true
ttl           59m12s
Green success on this runbook

Sealed=false. HA Mode: active on the address the job uses (or a VIP that lands there). Token policies include finance-read with remaining ttl. Policy path includes secret/data/finance/* and database/creds/finance-ro read. kv get shows version 7. lease lookup shows expire_time in the future and renewable=true. File audit is enabled before you promise who-read-what.

6. Runtime — renew, revoke, standby, KV

After go-live the request is no longer “enable AppRole.” It is this hop list. Official architecture: the client presents the token; Vault loads the attached policies; if the token has a lease it must be renewed or it is invalidated.

Flow 3 · runtime after login
CI / app X-Vault-Token Token store ttl 18m left ACL evaluate finance-read KV v2 /data/ · v7 DB lease hvle-… Audit file/ who hit which path Runtime traps on a healthy floor Standby + no forwarding + pinned address → write never reaches this row. Point VAULT_ADDR at active or VIP. token_ttl 20m on a 30m job → re-auth or use a periodic token. Batch tokens cannot renew. Revoke parent token → child tokens and all leases die. Orphan tokens from auth-method login do not.

Audit is last on purpose. You cannot prove a read that never hit a device. KV and database split after ACL — only one of them has a lease.

Renew. Official: vault token renew for the identity lease; vault lease renew -increment=3600 <lease_id> for a dynamic secret. Increment is from the current time. Periodic tokens reset TTL to the configured period on each successful renew and can live indefinitely until they miss a beat — or until an explicit max TTL. A token with both a period and an explicit max TTL behaves periodic, then dies at the hard cap.

Revoke. Official: revoke a lease and the provider credential is destroyed. Revoke a parent service token and the whole child tree plus its leases die. auth/token/revoke-orphan kills the token and orphans the children — use with care. Root tokens: only init, another root, or vault operator generate-root with a quorum of unseal/recovery keys. Revoke them after the emergency.

Standby. Official request forwarding is on by default. Clients may still pin a standby, send X-Vault-No-Request-Forwarding, or hit a VIP whose api_addr is wrong and loop on 307. cluster_addr is the server-to-server TLS channel (default listener port + 1, so 8201). Only the active process listens on the cluster port.

KV is not a lease. Official note on the lease page: the Key Value backend does not issue leases. Version 7 versus version 6 is a pin. Destroying version 7 to “roll back” without change-control is an incident you caused.

7. Traps + lease proof

SymptomLooks likeActuallyFirst move
Everyone 403, Sealed=true Policy outage Floor is dark — only unseal + status work vault status on the caller address, then unseal under change-control
One app 403, others fine, Sealed=false Cluster down ACL path / capability / namespace token lookup + policy read
Writes fail, reads work, HA Mode: standby Need to unseal again You are on a follower; forwarding off or client pinned raft list-peers; point at active / VIP
CLI kv get works, HTTP 404 on /v1/secret/finance/db Broken mount KV v2 API needs /data/ Compare CLI vs API path; fix client or ACL
Valid token, other business unit’s path Need secret/* Wrong namespace tree Name VAULT_NAMESPACE; login in that tree
Secret exists, app wants old version Vault lost the secret KV version pin — not a lease kv get version field; do not destroy v7 mid-incident
DB creds worked at 01:44, failed at 02:04 Need to reseal Lease expired; Vault revoked the username vault lease lookup on the stored lease_id
Job died after 24h Cluster flap secret_id_ttl or token_ttl design Read the AppRole; re-issue under change-control
Write 403 on finance-read Seal / HA bug ACL is read-only — least privilege working Do not add update without an owner
Nobody can prove who read payroll Need a wider ACL No audit device — official default is off vault audit list; say you cannot prove the past
Root token in Slack “until morning” Temporary fix Root can do anything, including never-expire Isolate, generate-root only with quorum, revoke after
Proof checklist — finance ticket is actually working
Interview close you can steal

Vault is a secrets factory. Unseal powers the floor. HA names the active desk. Auth prints a token that is the session. Policy is the door list on that token. The lease is the ticket that expires. I prove Sealed and HA Mode, then token policies, then the ACL path, then expire_time. Unsealed is not a secret. KV has no lease. Root is not a morning workaround.

Next lesson: walk the same commands as night-shift tickets on the Vault evidence desk. Dummy lab on the HashiCorp Vault hub.

Knowledge check

Six judgment questions. Map each miss back to the section named in the reason.

Q1

CI 403. vault status on the job’s address shows Sealed=false and HA Mode active. What is the first useful move?

Correct: b. Official status: Sealed=false means ready to operate. The 403 is now auth, policy, path, namespace, or lease. Re-read Why unsealed is not a secret and the factory path.
Q2

Official Authentication docs say the token Vault issues after login is conceptually similar to what?

Correct: b. Official auth concept: authenticate, generate a token, attach mapped policies. Recovery keys cannot decrypt the root key. Re-read Mental model station 2.
Q3

Generating database credentials is an HTTP GET on database/creds/finance-ro. Which capability must the ACL grant?

Correct: c. Official Policies note: generating database credentials creates a user at the provider, but the request is GET → read. Re-read Mental model station 3 and Side B.
Q4

App HTTP GET /v1/secret/finance/db 404s. vault kv get secret/finance/db works on the same KV v2 mount. The app also asks why there is no lease_id to renew. What is true?

Correct: b. CLI inserts /data/. Official lease page: KV does not issue leases. Re-read Side B, Side C, and Runtime.
Q5

Writes fail intermittently. The node in VAULT_ADDR shows HA Mode standby. Next action?

Correct: d. Official HA: one active lock holder; standbys forward by default or redirect 307. Unsealing an already-unsealed follower does nothing. Re-read Side A step 2 and Runtime.
Q6

What proves the finance dynamic-creds ticket is actually working?

Correct: c. Official lease fields. Sealed is the floor. Root is not proof. KV is a different station. Re-read Side C and the proof checklist.

Sources

Related: Vault evidence desk · HashiCorp Vault interview hub · Policy and namespace design · AppRole secret-zero · Dynamic secrets and leases · Audit device / SIEM pipeline