# OpenBao Unseal Custody Models 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 human custody gates as production trust increases. This is separate from **king custody mode** (`temporary-single-king`, `two-of-three-planned`, `two-of-three-ready`) which governs who holds platform recovery authority. Unseal custody models govern **how init/unseal executes** during bootstrap and rebuild. --- ## Models | Model ID | Label | Custody strength | Automation | Status | | --- | --- | --- | --- | --- | | `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) - Init/unseal material lives in **SOPS/age** custody bundle (not Git plaintext). - Applied by `sso-mfa/bootstrap/openbao-init-unseal.sh` (`make openbao-init-unseal`, NET-WP-0020 T2) after cluster + OpenBao pod exist. The helper enforces the console custody-model gate, initializes only when uninitialized (init JSON written straight into the age-custody secrets dir), replays unseal shares stdin-to-stdin, verifies post-unseal state, and emits non-secret `openbao_initialized` / `openbao_post_unseal_verified` evidence. Set `OPENBAO_RUN_CONFIGURE_INITIAL=1` to chain `railiance-platform: make openbao-configure-initial`. - Enables **unattended rebuild test cycles** on a 3-node slate. - **Not** production trust posture — use to prove S1→S3→SSH engine automation, then graduate to stronger models. ### `attended-ceremony` (production) - Human-attended `bao operator init`, out-of-band unseal share escrow, root token retirement — runbook: `docs/openbao-attended-ceremony-runbook.md` (command detail in `railiance-platform/docs/openbao.md`). - Matches first successful NetKingdom bootstrap (NET-WP-0015–0017). - 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) - OpenBao seal configuration uses **transit** or cloud KMS auto-unseal. - Pod restart without manual unseal threshold ceremony. - 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. --- ## Deployment profile 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**; gates express what evidence is still missing for the selected model. --- ## Console integration ```bash # List models and implementation status python3 tools/security-bootstrap-console/security_bootstrap_console.py \ openbao-unseal-custody-models # Select active model (only implemented models succeed) python3 tools/security-bootstrap-console/security_bootstrap_console.py \ select-openbao-unseal-custody-model \ --model sops-held-automation \ --metadata .local/security-bootstrap.json # Status shows gate: "OpenBao unseal custody model" make security-bootstrap-console # or: ... status --metadata .local/... ``` Metadata field: `openbao_unseal_custody_model` --- ## Automation chain (after model selected) | Step | Owner | Target | | --- | --- | --- | | S1 OS baseline | railiance-infra | 3 nodes | | S2 k3s HA | railiance-cluster | ThreePhoenix | | S3 OpenBao deploy | railiance-platform | `make openbao-deploy` | | Init/unseal apply | net-kingdom | `make openbao-init-unseal` (sops-held) | | Platform config | railiance-platform | `openbao-configure-initial` | | SSH engine | railiance-platform | `openbao-configure-ssh` (planned) | | Host CA trust | railiance-infra | `bootstrap-ssh-ca` (planned) | | Sign smoke | ops-warden | `warden sign` (WP-0008 T2) | --- ## Related docs - `docs/smooth-bootstrap-guide.md` — Step 5 (OpenBao init/unseal) - `docs/platform-root-custody.md` — king / quorum custody - `railiance-platform/docs/openbao.md` — deploy and ceremony - `ops-warden/wiki/OpenBaoSshEngineChecklist.md` — SSH engine verify - `ops-warden/history/2026-06-17-openbao-production-verify.md` — current blockers