generated from coulomb/repo-seed
NET-WP-0020 finished: attended-ceremony + auto-unseal-transit profiles, greenfield init/unseal proof
T2: greenfield live proof against a fresh uninitialized OpenBao 2.5.5 — caught and fixed 'bao operator unseal -' not reading stdin (now 'bao write sys/unseal key=-'); init and reseal-replay paths proven. T3: attended-ceremony selectable — runbook, non-secret ceremony-record template + validator, and a lab/production deployment profile that blocks sops-held-automation in console selection, gates, and the init script. T4: console gate + evidence flags for auto-unseal-transit (Helm seal stanza prepared in railiance-platform). Also: SCOPE.md refreshed to current repo state; adhoc fix for the broken check-secrets Make target (unescaped $). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
40
history/2026-07-02-openbao-greenfield-init-unseal-proof.md
Normal file
40
history/2026-07-02-openbao-greenfield-init-unseal-proof.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# OpenBao greenfield init/unseal proof (NET-WP-0020 T2)
|
||||
|
||||
Date: 2026-07-02
|
||||
Scope: `sso-mfa/bootstrap/openbao-init-unseal.sh` proven live against a
|
||||
genuinely uninitialized OpenBao 2.5.5 instance.
|
||||
|
||||
## Method
|
||||
|
||||
A fresh local `bao server` (file storage, throwaway scratchpad dir) was started
|
||||
uninitialized and sealed. A `kubectl` shim forwarded the script's
|
||||
`kubectl -n openbao exec openbao-0 -- bao …` calls to the local instance, so
|
||||
the script ran byte-for-byte unmodified logic against real OpenBao. Console
|
||||
metadata lived in a scratch file with `sops-held-automation` selected.
|
||||
|
||||
This substitutes for the "rebuild slate" run: it exercises the exact
|
||||
init/unseal/verify code paths on a greenfield instance. The first 3-node
|
||||
rebuild will re-run the same script through `creds-bootstrap-agent.sh`
|
||||
Phase 7b.
|
||||
|
||||
## Results
|
||||
|
||||
1. **Custody gate refusal** — with no model selected, the script refused
|
||||
(`unseal custody model is 'unselected'`). Matches earlier negative tests.
|
||||
2. **Bug found and fixed** — `bao operator unseal -` does **not** read the
|
||||
share from stdin (OpenBao treats `-` as the literal key: *"'key' must be a
|
||||
valid hex or base64 string"*; without an argument it demands a TTY). The
|
||||
live cluster never hit this because it was already unsealed. Fixed to
|
||||
`bao write sys/unseal key=-`, which reads the value from stdin — shares
|
||||
still never touch argv or logs.
|
||||
3. **Greenfield init path** — uninitialized → `operator init` (3 shares,
|
||||
threshold 2) → init.json written 0600 into the age-custody secrets dir →
|
||||
share replay stopped at threshold (share 2 of 3) → post-unseal verified.
|
||||
Evidence: `openbao_did_init_this_run=true`, `openbao_initialized=true`,
|
||||
`openbao_post_unseal_verified=true`.
|
||||
4. **Restart/reseal path** — server restarted (initialized + sealed) →
|
||||
script skipped init, replayed SOPS-held shares to threshold → verified.
|
||||
Evidence: `openbao_did_init_this_run=false`, both flags true.
|
||||
|
||||
Test server, storage, and init material were destroyed after the proof
|
||||
(init.json shredded).
|
||||
Reference in New Issue
Block a user