Vault Unseal Runbook
MOD stores its infrastructure secrets in Vault. This install runs Vault in
Shamir seal mode with manual unseal: after any restart of the Vault
container (a host reboot, a docker compose cycle, an out-of-disk eviction),
Vault comes back sealed and stays sealed until a human unseals it. Nothing
in the stack auto-unseals Vault from a file, on purpose — the key material
lives only on the key holders' machines.
This runbook is what the Dashboard's red "Vault is sealed" banner and the
VAULT_SEALED admin alert point at.
What "sealed" means
"Sealed" means Vault's key material is locked in memory and every secret is unreadable. The Vault server process is up and answering, but:
- Postgres credentials from
database/creds/*cannot be read, - S3/versitygw, SMTP (Stripe, Postmark), API keys and every other KV secret cannot be read,
- anything that reads a secret at startup will fail or fall back to cached credentials until they expire.
The rest of the platform keeps running on whatever it already holds; it does
not crash-loop. The API's seal monitor (services/vault_seal_monitor.py)
writes a VAULT_SEALED audit event and alerts the platform admin exactly once
per seal, and a VAULT_UNSEALED audit event when it recovers. The
boot-reconcile watchdog detects the sealed state and deliberately does not
restart Vault — restarting a sealed Vault never unseals it.
You are sealed if any of these is true:
- the Dashboard shows the red "Vault is sealed" banner (platform admins),
GET /health?extended=truereturns"vault_sealed": true,- from a machine that can reach Vault:
vault statusprintsSeal Status: sealed, ordocker exec my_vault vault operator seal-statusprints"sealed": true.
Who holds the shares
Vault was initialized with Shamir key shares: the unseal key is split into N shares, of which M are required (a threshold). The shares were printed exactly once at initialization (or when the key was rekeyed). The operators should have split them by the organization's standard ceremony — for example 1-of-3, 2-of-3, or 3-of-5 — so that M different holders each hold a different share and no single person can unseal alone.
- If you do not know how many shares exist or what the threshold is, check
docker exec my_vault vault operator unseal— after the first share it tells you how many more are needed. - If fewer than M shares can be recovered, Vault cannot be unsealed. The data
is still on the
vault_datavolume; recovery then means the rekey/restore path in Backup and Restore, which also needs the shares. Do not delete thevault_datavolume in this state.
How to unseal
From one of the key holders' machines (a laptop or admin box that can reach the install's Vault), not from the server:
-
Point
vaultat the install. The server's API address is usuallyhttp://<server>:8200on the internal network (or the mesh/tailnet address of this install):export VAULT_ADDR=http://<server>:8200 -
Run
vault operator unsealM times, each time with a different share, until the prompt printsSealed: false. Each share may only be used once per unseal — reusing the same share M times does nothing:$ vault operator unsealKey (enter without a newline): <share 1>Keys Required: 3Shares Required: 3Progress: 1/3repeat with share 2, then share 3. When done:
$ vault operator unsealKey (enter without a newline): <share 3>Sealed: false -
Verify:
$ vault statusSeal Status: unsealedThen check the platform: the Dashboard banner disappears, and
GET /health?extended=trueshows"vault_sealed": false. The API logs aVAULT_UNSEALEDaudit event within a minute.
Restoring a backup also needs the shares
A Vault backup (vault_data snapshot) is encrypted with the same key
material. Restoring a backup into a fresh Vault does not bypass unseal —
the fresh Vault comes up sealed and you must run the same
vault operator unseal dance with M different shares before the restored
secrets are readable. Keep this in mind when planning disaster recovery:
backup + shares = restorable; either one alone is not.
Notes
- Unsealing puts the key material in Vault's memory only; a restart seals it again. That is the point of the manual-unseal design.
- Never paste shares into chat, tickets, or logs. The API's audit trail records that Vault sealed/unsealed, but never a share.
- To change custody or rotate the keys later, run a rekey
(
vault operator rekey) as a ceremony — the old shares stop working and new shares are printed once.