NK-WP-0056-T10: attended OpenBao setup and proof for the executor lanes
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

tools/service-binds/executor-lanes.py (bind-lane.py shape): under both
sha256-bound, approved, binding-confirmed CCRs (0058 write, 0059 journey) and
an attended platform-admin, apply both policies, set cas_required on the
svc-authelia key, create the standing journey-read role, refuse if the
window-scoped write role exists, prove the agent fence; verify proves the
journey token reads only its path (<=15m) and denies wrong SA, wrong audience
and write-role login. Value-free receipts. 12 tests on a fake OpenBao (real
helpers), in make bounded-executor-test. Founder runbook:
sso-mfa/k8s/bounded-executor/T10-LANES-RUNBOOK.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5502@bnt-lap001
Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196
This commit is contained in:
tegwick 2026-10-31 19:15:46 +01:00
parent 37f4d4f306
commit 634b3a41df
4 changed files with 479 additions and 1 deletions

View file

@ -0,0 +1,73 @@
# T10 runbook: executor standing objects and OpenBao lanes (founder-run)
NK-WP-0056-T10. Three steps, about 15 minutes. Nothing here starts a Job or touches the svc-authelia value. The
bind write role (CCR-2026-0058) is **not** created: it exists only inside an admitted window.
| Step | Where | What changes |
| --- | --- | --- |
| 1 | `~/rapp-bounded-executor` | creates ServiceAccount `nk-bind-executor`, its Role and RoleBinding, and NetworkPolicy `bounded-executor` in `sso` |
| 2 | `~/railiance-platform` | records `binding_confirmed` in CCR-2026-0058 and CCR-2026-0059 |
| 3 | `~/net-kingdom` | OpenBao: both policies, `cas_required` on the svc-authelia key, the standing journey-read role, and proof |
## 1. Standing objects (rapp)
```bash
cd ~/rapp-bounded-executor && git pull --ff-only
K="kubectl --kubeconfig $HOME/.kube/config-railiance01"
make server-dry-run KUBECTL="$K" # 4 objects "serverside-applied (server dry run)"
make deploy KUBECTL="$K" # the same 4 objects, without "(server dry run)"
make verify-live KUBECTL="$K" # {"role_matches_ceiling": true, "standing_objects_present": true, ...}
```
The pod runs nothing yet: no Job exists until `make run` under an admission.
## 2. Confirm the binding (railiance-platform)
The CCRs bind `service_account_names: [nk-bind-executor]` in `sso`, audience `openbao`. Confirm that this
ServiceAccount now exists, as declared:
```bash
cd ~/railiance-platform && git pull --ff-only
UID_SA=$($K -n sso get serviceaccount nk-bind-executor -o jsonpath='{.metadata.uid}'); echo "$UID_SA"
for C in CCR-2026-0058 CCR-2026-0059; do
scripts/credential-change.py confirm-binding "$C" --reviewer platform-owner --comment \
"Binding confirmed: ServiceAccount nk-bind-executor in namespace sso only (uid $UID_SA), audience openbao, from rapp-bounded-executor."
done
git status --short # exactly the two CCR files modified
```
## 3. OpenBao lanes (attended platform-admin)
```bash
cd ~/net-kingdom && git pull --ff-only
bao login -method=oidc -path=netkingdom role=platform-admin # MFA; the tool fails closed without it
W=$(sha256sum ~/railiance-platform/credential-change-requests/CCR-2026-0058-*.yaml | cut -d' ' -f1)
J=$(sha256sum ~/railiance-platform/credential-change-requests/CCR-2026-0059-*.yaml | cut -d' ' -f1)
E=docs/evidence/$(date +%F)-nk56-t10-executor-lanes; mkdir -p "$E"
python3 tools/service-binds/executor-lanes.py setup --write-ccr-sha256 "$W" --journey-ccr-sha256 "$J" \
--receipt "$E/01-setup.json" # {"status": "lanes_prepared", "phase": "done"}
python3 tools/service-binds/executor-lanes.py verify --write-ccr-sha256 "$W" --journey-ccr-sha256 "$J" \
--kubeconfig "$HOME/.kube/config-railiance01" --receipt "$E/02-verify.json" # {"status": "lanes_verified", ...}
```
`setup` is idempotent: it creates what is missing and refuses on any drift. It never changes the coding-agent fence,
because CCR-2026-0053 and CCR-2026-0057 established it; it only proves the fence. Receipts hold no values. `verify`
reads the journey entry into memory only to check its field names.
If a step stops, the receipt's `phase` and `reason` say where:
| `reason` | Meaning, next step |
| --- | --- |
| `write:ccr_digest` / `journey:ccr_digest` | the CCR changed after `W`/`J` were computed; compute them again |
| `*:binding_unconfirmed` | step 2 not done (or not saved) |
| `attended_platform_admin_required` | no `bao login` as platform-admin, or a root token |
| `agent_fence_missing` | the boundary policy lacks a deny line for one of the two paths; stop and hand to claude-code |
| `command_failed` in phase `cas_required` | platform-admin may not patch KV metadata; hand to claude-code |
| `write_role_exists_outside_a_window` | someone created the window-scoped write role; delete it, or stop |
| `*:policy_drift` | a policy of that name exists with other text; stop |
| `negative_login_accepted` / `journey_capabilities` | the role is wider than approved; delete the journey role and stop |
## 4. Afterwards
Tell claude-code. It commits the two CCRs and the receipts, moves CCR-2026-0059 on, and records T10 progress.