Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 295952@bnt-lap001 Assistant-Session: e93f64ad-516c-46eb-9666-aad8d300c477
109 lines
9.2 KiB
Markdown
109 lines
9.2 KiB
Markdown
# Is v0.2 expressive enough? Mapping the security bootstrap console
|
|
|
|
Status: analysis, 2026-09-29 (RBT-WP-0009-T05; closes RBT-WP-0005-T03).
|
|
|
|
The plan for adopting `runbook-pack/v0.2` said: use the NetKingdom security bootstrap console
|
|
(`net-kingdom/tools/security-bootstrap-console/`, 5,300 lines, invented in NET-WP-0016) as the first real test. If the model
|
|
can express its stages, gates and runbooks without special cases, it is expressive enough. This is that test, done from the
|
|
console's own definitions (read from its running `/api/status` and its source, against a throwaway metadata file).
|
|
|
|
## Verdict
|
|
|
|
**The structure maps; the behaviour does not fully.** v0.2 expresses the console's stages, gates, actors, dimensions, artefacts,
|
|
evidence validators, typed approval and alternatives. It does not yet express five behaviours the console relies on: conditional
|
|
applicability, re-evaluation of gates that can regress, outputs of one member feeding the next, local-only attributes, and
|
|
gates satisfied by an automation path. So v0.2 is adequate for **procedures** (every runbook in the console, and the three
|
|
NetKingdom packs) and **not yet proven adequate for a long-lived staged bootstrap** as a whole. Decision: the console stays a permanent
|
|
legacy pack (RBT-WP-0005-T05); extracting its engine parts (T04) is moved to the backlog until the gaps below are closed.
|
|
|
|
## What the console contains
|
|
|
|
| Element | Count | Notes |
|
|
| --- | --- | --- |
|
|
| Stages | 6 | S1 Low-trust assembly, S2 King credential preparation, S3 OpenBao bootstrap, S4 Admin identity integration, S5 Cleanup and hardening, S6 Reopen under custody |
|
|
| Top-level gates | 14 | statuses `done`, `blocked`, `human`, `automation` |
|
|
| Sub-checklists | 11 + 4 + 4 | king-credential kit items, key-custody items, admin-identity integrations |
|
|
| Section statuses | 9 | view-level completeness of the UI's own sections, not gates |
|
|
| Roles | 6 | setup-operator, platform-root-custodian, identity-admin, openbao-ceremony-operator, recovery-custodian, future-quorum-custodian; each with a designated contact |
|
|
| Subsystems, integrations | 6 + 6 | LLDAP, privacyIDEA, KeyCape, OpenBao, custodian age envelope, bootstrap bundle |
|
|
| Runbooks | 7 | all `template` state; 23 copyable command blocks in total |
|
|
| Artefacts | 12 | references only (a password-safe entry, an age key location, unseal shares held elsewhere); states nil, set, ok |
|
|
| Approval | 1 | typed phrase `approve custody mode`, two approvable modes |
|
|
|
|
## How the console works, which decides the mapping
|
|
|
|
1. **A persistent fact document** (`.local/security-bootstrap.json`, flat keys such as `openbao_initialized`). It lives for weeks.
|
|
2. **The stage is derived from the facts** (`derive_stage`: the most advanced fact wins), not from stepping through a list.
|
|
3. **Gates are computed on every view**, from the facts and from live probes (files present, a Secret deployed in the cluster). A gate can go
|
|
back from done to blocked when the system changes.
|
|
4. **Gate status is a small vocabulary**: `done`; `blocked` (a precondition is missing); `human` (ready, waiting for a person);
|
|
`automation` (satisfied by an unattended path, for example the SOPS-held init).
|
|
5. **Applicability depends on choices**: the unseal custody model (sops-held, attended ceremony, auto-unseal) changes which init gate
|
|
applies, and the production profile forbids one of them.
|
|
|
|
## The 14 gates
|
|
|
|
| # | Gate | Stage (proposed) | v0.2 form | Verdict |
|
|
| --- | --- | --- | --- | --- |
|
|
| 1 | King credential kit | S2 | gate `datapoints_ok` over the 11 kit items (datapoints, confirmed by steps) | direct |
|
|
| 2 | Custody strategy approval | S2 | irreversible step with `confirm_phrase: approve custody mode`; gate on the `custody_mode` datapoint | **caveat G4**: only some modes may approve live init; needs a value predicate, or an enum limited to the approvable modes |
|
|
| 3 | OpenBao preflight | S3 | gate check `command`, exit 0 (`make ... openbao-status`) | direct |
|
|
| 4 | OpenBao unseal custody model | S3 | enum datapoint `custody_model`; the production profile blocks one value | **caveat G4** (cross-datapoint rule) and G1 |
|
|
| 5 | OpenBao init ceremony | S3 | step with alternatives (attended ceremony / automated init), recommended by `custody_model` | alternatives fit, but the automated path is executed by a script: **needs execution (G6)**, and refusing live init under some profiles is G1 |
|
|
| 6 | OpenBao initial configuration | S3 | step, then gate on an evidence datapoint | direct |
|
|
| 7 | KeyCape OpenBao client definition | S4 | gate check `command` probing the source | direct; **G3** (recheck) |
|
|
| 8 | KeyCape OpenBao client deployed | S4 | gate check `command` probing the live Secret | direct; **G3** |
|
|
| 9 | OpenBao OIDC auth | S4 | step plus evidence datapoint | direct |
|
|
| 10 | OIDC admin login | S4 | manual check (a browser login through KeyCape and MFA), plus a claims check by command | direct |
|
|
| 11 | Root-token disposition | S5 | enum datapoint limited to `revoked` and `offline-sealed`; gate `datapoints_ok` | direct |
|
|
| 12 | Restore drill | S5 | a separate pack (7 command blocks, evidence validator); gate check runs the validator | **caveat**: needs a dependency between runbooks (`requires_packs`, RBT-WP-0006-T04), or the drill inlined |
|
|
| 13 | Cleanup and rotation | S5 | gate with several manual checks | direct |
|
|
| 14 | Platform reopen | S6 | gate check by the custodian actor, with an irreversible confirmation | direct |
|
|
|
|
**Ten map directly, three with a caveat, one needs execution.** The console does not tie gates to stages explicitly; v0.2 does, which is
|
|
the improvement asked for in the UX review (each gate belongs to one stage and names its quality goal). The sub-checklists map to
|
|
datapoints and steps in the stage they belong to.
|
|
|
|
## The rest of the model
|
|
|
|
| Console | v0.2 | Fit |
|
|
| --- | --- | --- |
|
|
| Stages S1 to S6 | `stages`, completion derived from members | good; order by `requires` |
|
|
| Roles with designated contacts | `actors`, plus a datapoint per contact carrying the `actor` dimension | good; see G5 for the contacts |
|
|
| Subsystems | the `subsystem` dimension on datapoints | good; the data view already groups by it |
|
|
| Artefacts (nil, set, ok) | `artefacts` with a location datapoint | good; artefact state is derived from the location datapoint |
|
|
| The 7 runbooks | 7 native packs | good and independent of the gaps: each is a linear procedure with commands |
|
|
| The 23 command blocks | step commands; the interactive `read -rs` prompts stay operator-run | good; nothing secret is ever entered into the engine |
|
|
| Typed approval phrase | `confirm_phrase` on an irreversible step | good |
|
|
| Evidence validators (`validate-*`) | gate or step checks by `command`, exit 0 | good |
|
|
| Copyable command blocks, next action | the guided flow | the new UI does both |
|
|
|
|
## The gaps
|
|
|
|
These are candidates for a v0.3. None blocks closing the runbook-tutorials workplans, and none affects the procedures that exist today.
|
|
|
|
- **G1 Conditional applicability.** Stages, steps and gates that apply only for some choices (`applies_when` on a datapoint value). `one_of`
|
|
chooses between alternatives inside a step; it cannot switch a whole gate on or off.
|
|
- **G2 A longer horizon.** A run untouched for seven days counts as abandoned. A multi-week ceremony needs a per-pack (or per-run) horizon.
|
|
- **G3 Re-evaluating a gate.** A passed gate is final in a run. The console's gates regress when the system changes. A gate needs a recheck,
|
|
and a passed gate that fails a recheck needs a state of its own.
|
|
- **G4 Value predicates.** `datapoints_ok` only asks that a datapoint is `ok`. The console needs "this datapoint is one of these values" and
|
|
rules across two datapoints (`production` excludes `sops-held-automation`).
|
|
- **G5 Local-only attributes.** The console keeps role contacts (email addresses) in an ignored `.local` file. Attribute sets and project
|
|
files are meant to be committed, so personal data would land in git. An attribute needs a `local` visibility that is never written into a
|
|
repository file.
|
|
- **G6 Gates satisfied by an automation path.** The console's `automation` status means an unattended script did the work. Auto-confirm
|
|
only confirms; running the script is the opt-in execution level (RBT-WP-0006-T01).
|
|
- **G7 Outputs feed later members.** A project run snapshots its attributes at the start. Facts established by one member (the custody
|
|
model chosen in S2, "OpenBao initialized" in S3) do not flow into the members after it. A staged bootstrap as a project needs that flow.
|
|
|
|
## Consequences
|
|
|
|
- **The seven runbooks and the three NetKingdom packs can be native v0.2 packs now.** The three NetKingdom packs are ported in
|
|
RBT-WP-0009-T06. The seven console runbooks are ready to port as a separate content task in net-kingdom; they need none of G1 to G7.
|
|
- **The console stays.** It is a permanent legacy pack, launched unchanged. What it does well and v0.2 cannot yet do (live probes,
|
|
regression, a fact store that outlives a session, conditional gates) is exactly G1, G3, G5 and G7.
|
|
- **The engine extraction (RBT-WP-0005-T04) waits for G1, G3 and G7.** Extracting the generic parts first would freeze the console's
|
|
workarounds into the engine.
|
|
- **The console is a project, not a run.** The right long-term shape is a project whose members are runbook packs per stage, with facts
|
|
flowing between them (G7). That is a design task for a v0.3, not a migration.
|