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>
3.3 KiB
OpenBao Attended Ceremony Runbook
Date: 2026-07-02
Status: active — production custody model (attended-ceremony, NET-WP-0020 T3)
Human-attended OpenBao init/unseal for production trust posture. The security
bootstrap console never runs bao operator init (refuse-live-init
boundary) — this runbook is executed by the openbao-ceremony-operator role
and evidenced by a non-secret ceremony record.
Contrast with sops-held-automation (lab posture): there, root token and
unseal shares live together in one SOPS bundle for unattended rebuild loops.
The attended ceremony keeps unseal shares out of band and retires the root
token, so no single artifact can open the platform.
Preconditions
-
Console gates green up to the init ceremony:
make security-bootstrap-console— custody strategy approved, preflight passed. -
Select profile and model (production blocks the lab default):
python3 tools/security-bootstrap-console/security_bootstrap_console.py \ --metadata .local/security-bootstrap.json \ select-deployment-profile --profile production python3 tools/security-bootstrap-console/security_bootstrap_console.py \ --metadata .local/security-bootstrap.json \ select-openbao-unseal-custody-model --model attended-ceremony -
OpenBao deployed and reachable:
make -C ../railiance-platform openbao-status(expect uninitialized/sealed on greenfield). -
Two people present (operator + witness) where the custody roster requires it; unseal-share escrow destinations agreed per
docs/platform-root-custody.md(signed custody roster).
Ceremony
Follow railiance-platform/docs/openbao.md for the exact commands. Outline:
- Init — operator runs
bao operator init(3 shares, threshold 2) directly against the pod from a terminal. Output goes only to the operator's screen — never into the console, chat, State Hub, or files inside a Git checkout. - Escrow — each unseal share is transcribed to its escrow destination (offline packet / password safe per roster). No two shares in the same custody location.
- Unseal — replay threshold shares; verify
initialized=true sealed=false. - Root retirement — use the root token only for the initial
configuration handoff (
make -C ../railiance-platform openbao-configure-initial), then revoke it (bao token revoke -self) or escrow it per roster; record the disposition.
Evidence
Record the ceremony in a non-secret JSON record and validate it:
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
openbao-ceremony-record-template > .local/openbao-ceremony-record.json
# edit: dispositions, dates, roles — NEVER shares, tokens, or key material
make security-bootstrap-validate-openbao-ceremony-record
The validator refuses records containing secret-looking markers (tokens, key
blocks, otpauth URIs) or leftover template placeholders. After a valid
record, set the console flags (openbao_initialized,
openbao_post_unseal_verified) in the metadata so the gates advance.
Related
docs/openbao-unseal-custody-models.md— model frameworkdocs/platform-root-custody.md— custody roster and share holdersdocs/security-bootstrap-openbao-ceremony-ux.md— operator UX notesrailiance-platform/docs/openbao.md— deploy + command-level ceremony