83 lines
3.3 KiB
Markdown
83 lines
3.3 KiB
Markdown
|
|
# 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
|
||
|
|
|
||
|
|
1. Console gates green up to the init ceremony:
|
||
|
|
`make security-bootstrap-console` — custody strategy approved, preflight
|
||
|
|
passed.
|
||
|
|
2. Select profile and model (production blocks the lab default):
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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
|
||
|
|
```
|
||
|
|
|
||
|
|
3. OpenBao deployed and reachable:
|
||
|
|
`make -C ../railiance-platform openbao-status` (expect uninitialized/sealed
|
||
|
|
on greenfield).
|
||
|
|
4. 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:
|
||
|
|
|
||
|
|
1. **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.
|
||
|
|
2. **Escrow** — each unseal share is transcribed to its escrow destination
|
||
|
|
(offline packet / password safe per roster). No two shares in the same
|
||
|
|
custody location.
|
||
|
|
3. **Unseal** — replay threshold shares; verify
|
||
|
|
`initialized=true sealed=false`.
|
||
|
|
4. **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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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 framework
|
||
|
|
- `docs/platform-root-custody.md` — custody roster and share holders
|
||
|
|
- `docs/security-bootstrap-openbao-ceremony-ux.md` — operator UX notes
|
||
|
|
- `railiance-platform/docs/openbao.md` — deploy + command-level ceremony
|