net-kingdom/runbooks/openbao-operating-path/pack.yaml
tegwick 90112f3ca7
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
Port the NetKingdom packs to runbook-pack/v0.2 (ssh, openbao, flex-auth); update NK-WP-0044
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
2026-09-29 21:40:47 +02:00

239 lines
10 KiB
YAML

spec: runbook-pack/v0.2
id: nk.openbao-operating-path
title: "OpenBao: consume, attend, recover"
owner: net-kingdom
outcome: You can reach the already-deployed private OpenBao, know which owner serves a credential, know the custody model and the attended recovery path, and have seen the ceremony-record validator refuse a secret marker.
engine: native
framing:
- Init output, unseal shares and tokens go to the operator's screen only, never to chat, State Hub, logs or a Git checkout.
- Never use a public Bao URL; bao.coulomb.social is retired.
- Never place the root token and unseal shares in one artifact outside a lab.
- This pack never initializes or unseals the live estate. Greenfield deployment is a lab exercise and is not part of it.
actors:
- id: operator
role: Operator
description: Reaches OpenBao through the named tunnel with their own identity and reads what they are entitled to.
privileges: [open-tunnel, read-routed-secret]
datapoints:
- id: need
label: The credential you need
type: text
default: read a database password
help: Plain words; used only to look up the owner.
dimensions: {actor: operator, kind: request, subsystem: ops-warden}
ask_in: access
- id: tunnel
label: OpenBao tunnel
type: string
default: openbao-ui-railiance01
pattern: "[a-z0-9-]+"
help: The named ops-bridge tunnel; never a public Bao URL (bao.coulomb.social is retired).
dimensions: {kind: target, subsystem: ops-bridge}
ask_in: access
- id: record_state
label: Has an attended ceremony produced a record yet?
type: enum
values: [exists, none-yet]
default: none-yet
help: Decides which way the record step is recommended. Only meaningful after an attended ceremony.
dimensions: {kind: state, subsystem: openbao}
ask_in: records
- id: evidence
label: Ceremony record path
type: path
default: .local/openbao-ceremony-record.json
help: Relative to the net-kingdom checkout.
dimensions: {kind: location, subsystem: openbao}
ask_in: records
- id: probe
label: Scratch path for the negative probe
type: path
default: .local/ceremony-negative-probe.json
help: Created and removed by the probe step.
dimensions: {kind: location, subsystem: openbao}
ask_in: records
stages:
- id: access
title: Reach OpenBao
goal: You know who owns the credential and the private tunnel to OpenBao is up and healthy.
steps:
- id: prerequisites
title: Confirm the prerequisites
actor: operator
owner: workstation
description: "The bridge CLI and the named tunnel definition (ops-bridge); the warden CLI for credential routing (ops-warden); OpenBao already deployed and private (railiance-platform); a net-kingdom checkout, because commands run from its root (net-kingdom)."
idempotent: idempotent
verify:
done_when: All four prerequisites hold
expect: manual
- id: route
title: Find who owns the credential
actor: operator
owner: ops-warden
requires: [prerequisites]
uses: [need]
command: warden route find "{{need}}" --json | head -30
idempotent: idempotent
evidence: [owner_repo]
verify:
done_when: You know which repository owns the credential and that warden only routes, it does not vend
expect: manual
- id: tunnel-status
title: Check the OpenBao tunnel is connected
actor: operator
owner: ops-bridge
requires: [route]
uses: [tunnel]
command: bridge status
idempotent: idempotent
verify:
done_when: The tunnel row shows connected
command: bridge status | grep -E "{{tunnel}} +connected"
expect: exit-0
- id: tunnel-check
title: Run the end-to-end tunnel diagnostic
actor: operator
owner: ops-bridge
requires: [tunnel-status]
uses: [tunnel]
command: bridge check {{tunnel}}
idempotent: idempotent
verify:
done_when: The diagnostic passes
command: bridge check {{tunnel}}
expect: exit-0
gates:
- id: access-ready
title: OpenBao is reachable over its private tunnel
goal: private-access
blocking: true
downstream_risk: Reading secrets over an unhealthy or public path would put values where they must not go.
checks:
- done_when: The tunnel shows connected
command: bridge status | grep -E "{{tunnel}} +connected"
expect: exit-0
- done_when: The end-to-end diagnostic passes
command: bridge check {{tunnel}}
expect: exit-0
- id: custody
title: Know the custody
goal: You know the unseal custody model in force and the attended recovery path.
requires: [access]
steps:
- id: custody-models
title: See the unseal custody models
actor: operator
owner: net-kingdom
command: python3 tools/security-bootstrap-console/security_bootstrap_console.py openbao-unseal-custody-models
idempotent: idempotent
verify:
done_when: attended-ceremony is listed as implemented
command: python3 tools/security-bootstrap-console/security_bootstrap_console.py openbao-unseal-custody-models | grep -q attended-ceremony
expect: exit-0
- id: console-gates
title: Read the custody gates for the selected model
actor: operator
owner: net-kingdom
requires: [custody-models]
command: make security-bootstrap-console
idempotent: idempotent
verify:
done_when: You have read every gate and know which are met and which are not
expect: manual
- id: recovery-read
title: Read the attended recovery path
actor: operator
owner: net-kingdom
requires: [console-gates]
command: sed -n 1,82p docs/openbao-attended-ceremony-runbook.md
idempotent: idempotent
verify:
done_when: You can state who must be present, where each unseal share goes, and when the root token is revoked
expect: manual
gates:
- id: custody-understood
title: The custody path is understood
goal: attended-custody
blocking: true
checks:
- done_when: You can name the custody model, who must be present at a ceremony, and where each unseal share goes
expect: manual
- id: records
title: The evidence rules
goal: You have seen the ceremony-record validator refuse a secret marker, and know where a real record stands.
requires: [custody]
steps:
- id: probe-refused
title: Watch the ceremony-record validator refuse a secret marker
actor: operator
owner: net-kingdom
uses: [probe]
description: Writes a scratch file holding a fake token-shaped marker, runs the validator on it, and removes the file. The marker is assembled at run time so this pack never contains one.
command: |
printf '{"note":"%s%s"}\n' hvs. AAAAAAAAAAAAAAAA > {{probe}}
make security-bootstrap-validate-openbao-ceremony-record EVIDENCE={{probe}} 2>&1 | grep "secret-looking marker present"
rm -f {{probe}}
idempotent: idempotent
idempotent_note: Writes a scratch file and removes it in the same command.
rollback: rm -f the probe file; nothing else is written.
verify:
done_when: The validator names a secret-looking marker as a reason for refusal
command: |
printf '{"note":"%s%s"}\n' hvs. AAAAAAAAAAAAAAAA > {{probe}}
make security-bootstrap-validate-openbao-ceremony-record EVIDENCE={{probe}} 2>&1 | grep -q "secret-looking marker present"
r=$?
rm -f {{probe}}
exit $r
expect: exit-0
- id: ceremony-record
title: Look at the ceremony record
actor: operator
owner: net-kingdom
requires: [probe-refused]
uses: [record_state, evidence]
description: A real record exists only after an attended ceremony. Choose the way that matches where you are; the recommended one follows the answer you gave.
idempotent: idempotent
one_of:
- id: validate-record
title: Validate the real ceremony record
recommended_when: {record_state: [exists]}
command: make security-bootstrap-validate-openbao-ceremony-record EVIDENCE={{evidence}}
verify:
done_when: The validator passes on the ceremony record
command: make security-bootstrap-validate-openbao-ceremony-record EVIDENCE={{evidence}}
expect: exit-0
- id: no-record-yet
title: No ceremony has been held yet
recommended_when: {record_state: [none-yet]}
verify:
done_when: You know that no attended ceremony has produced a record, so there is nothing to validate yet
expect: manual
gates:
- id: evidence-rules-seen
title: The evidence rules are understood
goal: no-secrets-in-evidence
blocking: true
checks:
- done_when: The validator refused a secret-looking marker, and you know where a real record stands
expect: manual
- id: use
title: Read one secret
goal: You read one secret you are entitled to, from the path routing named, with your own identity.
requires: ["gate:access-ready", records]
steps:
- id: read-secret
title: Read one secret you are entitled to
actor: operator
owner: railiance-platform
auto_confirm: manual-only
description: Authenticate with your own identity and read only the path the routing result names, following railiance-platform/docs/openbao.md. Never paste the value anywhere.
idempotent: idempotent
rollback: Close the session; the read changes no state. If a value was exposed, treat it as compromised and rotate it through its owner.
verify:
done_when: You read only the routed path with your own identity and no value was pasted into chat, logs, State Hub or a checkout
expect: manual
ownership:
- {concern: "OpenBao deployment, configuration and unseal execution", owner: railiance-platform}
- {concern: Custody canon and the ceremony-record validator, owner: net-kingdom}
- {concern: Tunnel, owner: ops-bridge}
- {concern: Credential routing, owner: ops-warden}