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:
2026-07-02 22:08:33 +02:00
parent 60b9d7037d
commit 85a781b7a4
10 changed files with 564 additions and 69 deletions

View File

@@ -0,0 +1,82 @@
# 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

View File

@@ -1,7 +1,8 @@
# OpenBao Unseal Custody Models
Date: 2026-06-17
Status: framework — automation path active; production paths planned
Date: 2026-06-17 (updated 2026-07-02)
Status: all three models implemented — automation path proven greenfield;
production models gated by deployment profile and evidence
NetKingdom bootstrap must support **three** OpenBao init/unseal custody models.
Development starts with **maximum automation** for fast test cycles, then adds
@@ -18,9 +19,9 @@ during bootstrap and rebuild.
| Model ID | Label | Custody strength | Automation | Status |
| --- | --- | --- | --- | --- |
| `sops-held-automation` | SOPS-held unseal | Lab / fast iteration | High | **Implemented** (console + creds agent path) |
| `attended-ceremony` | Attended ceremony | Production | Low | Planned |
| `auto-unseal-transit` | Auto-unseal (transit/KMS) | Production HA | High | Planned |
| `sops-held-automation` | SOPS-held unseal | Lab / fast iteration | High | **Implemented** (console + creds agent path; greenfield-proven 2026-07-02) |
| `attended-ceremony` | Attended ceremony | Production | Low | **Implemented** (runbook + ceremony-record validator) |
| `auto-unseal-transit` | Auto-unseal (transit/KMS) | Production HA | High | **Implemented** (Helm seal stanza prepared; gate blocked until seal configured + verified) |
### `sops-held-automation` (default for greenfield dev)
@@ -37,32 +38,42 @@ during bootstrap and rebuild.
- **Not** production trust posture — use to prove S1→S3→SSH engine automation,
then graduate to stronger models.
### `attended-ceremony` (production target)
### `attended-ceremony` (production)
- Human-attended `bao operator init`, out-of-band unseal share escrow, root token
retirement — per `railiance-platform/docs/openbao.md`.
retirement — runbook: `docs/openbao-attended-ceremony-runbook.md`
(command detail in `railiance-platform/docs/openbao.md`).
- Matches first successful NetKingdom bootstrap (NET-WP-00150017).
- Console keeps **refuse-live-init** boundary; ceremony runbooks only.
- Console keeps the **refuse-live-init** boundary; the ceremony is evidenced by
a non-secret record validated with `validate-openbao-ceremony-record`
(`make security-bootstrap-validate-openbao-ceremony-record`).
### `auto-unseal-transit` (production HA target)
### `auto-unseal-transit` (production HA)
- OpenBao seal configuration uses **transit** or cloud KMS auto-unseal.
- Pod restart without manual unseal threshold ceremony.
- Requires `railiance-platform` Helm seal stanza + KMS provisioning.
- Seal stanza prepared (disabled by default) in
`railiance-platform/helm/openbao-values.yaml`; enable + migrate per
`railiance-platform/docs/openbao.md` "Auto-Unseal via Transit Seal".
- Console init gate stays **blocked** until `openbao_transit_seal_configured`
and `openbao_auto_unseal_verified` are set in the non-secret metadata.
---
## Development strategy
## Deployment profile
```text
1. Implement automation path (sops-held-automation)
→ SSH engine, warden sign, host CA trust, 3-node rebuild loops
2. Add attended-ceremony gates (block automation defaults in production profile)
3. Add auto-unseal-transit for HA ThreePhoenix rebuilds
The console metadata carries a `deployment_profile` (`lab` default,
`production`). The **production profile blocks `sops-held-automation`** — its
SOPS bundle holds root token and unseal shares together, which is lab posture
only. Selection, status gates, and `openbao-init-unseal.sh` all enforce the
block:
```bash
make security-bootstrap-select-deployment-profile PROFILE=production
```
Each model is selectable in the **security bootstrap console**. Unimplemented
models are **blocked** with a hint pointing to the active automation path.
Each model is selectable in the **security bootstrap console**; gates express
what evidence is still missing for the selected model.
---