railiance-platform/docs/credential-lane-designs/bounded-executor.md
codex c20bf329fd
All checks were successful
CCR intake gate / gate (push) Successful in 1m11s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
CCR-2026-0058: drop required_parameters from the write policy; back to proposed for re-approval
OpenBao 2.5.4 applies required_parameters to reads, so the executor could not
read the version it must name for CAS (net-kingdom NK-WP-0056-T12 synthetic
pilot). cas_required on the key still refuses writes without options.cas;
metadata, delete, sibling and new paths stay denied (tested). Renderer, test
and policy file corrected.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 994874@bnt-lap001
Assistant-Session: 6017c416-d619-47eb-bd1a-f670a02d7d87
2026-10-31 16:24:47 +01:00

7.7 KiB

Bounded executor: OpenBao lanes and audit sender (owner answer, NK-WP-0056-T02)

Owner answer from railiance-platform to NetKingdom's request (net-kingdom docs/proposals/2026-10-31-nk56-t02-owner-requests.md §railiance-platform; State Hub message 9d08288d). Basis: Bounded Execution Admission v0.1 (proposed) and its pilot example bind-rotation-svc-authelia.yaml. Workplan: workplans/RPF-WP-0069-bounded-executor-lanes.md.

Everything here is source and proposals. No role, policy, Secret or KV value was created or read. CCR-2026-0058 is proposed; approvals and the founder's choices below stay open.

Q1. Kubernetes auth role for sso/nk-bind-executor: which request types?

Answer: one role per lane, all bound to the one ServiceAccount, two request types.

The existing workload-kv-read contract requires a role to carry exactly its own policy (scripts/credential-change.py validate_workload_kv_read, "openbao.auth.policies must contain exactly the policy used by the auth method"; applier check "must contain only openbao.policy_name"). We keep that rule. The executor logs in once per lane with the same projected ServiceAccount token (audience openbao); each token carries one policy and lives at most 15 minutes. A combined role would make every lane's review depend on every other lane.

Executor need Request type Status
Write the next version of platform/workloads/net-kingdom/directory-binds/svc-authelia (CAS) and read it for checks/revert (T06) workload-kv-write-next-version (new, scripts/workload_kv_write_next_version.py) Type in source; CCR-2026-0058 proposed
Read platform/workloads/net-kingdom/synthetic-journey/syn-journey (PASSWORD, TOTP_SEED) for the journey (T10) workload-kv-read, native workload login (token_self_lifecycle: true, metadata_read: false), as the native reader proof in CCR-2026-0053 Not drafted; see below
LLDAP credential to set svc-authelia's password workload-kv-read of a new custody entry, after secrets-engine answers its Q2 Not drafted
audit-core sender bearer (receipts) workload-kv-read with ESO delivery, as CCR-2026-0021/0022 Not drafted; see Q2

The new type workload-kv-write-next-version

Prepared the way attended-service-credential-delivery was added: module scripts/workload_kv_write_next_version.py, tests tests/test_workload_kv_write_next_version.py, dispatch in scripts/credential-change.py (validate, plan, operator-commands, runbook). It is contract-only: there is no delegated applier (it is not in LANE_MODULES). The attended platform-admin applies policy and role from a reviewed commit, like CCR-2026-0052..0055.

The contract refuses anything wider than:

  • one exact platform/workloads/... path on mount platform; no wildcard, no sibling;
  • policy (generated by policy_hcl, artifact openbao/policies/<policy>.hcl): read + update on platform/data/<path> only (no required_parameters: OpenBao applies it to reads too, NK-WP-0056-T12), allowed_parameters = {data, options}; plus lookup-self/revoke-self. No create (a missing path is refused, so the executor cannot mint new entries), no metadata/, delete/, destroy/, undelete/, list;
  • key-level cas_required = true, set by the attended platform-admin at setup. The engine then refuses every write that does not name the version it replaces; races and replays fail closed in OpenBao, not in executor code. (required_parameters = ["options"] alone cannot force options.cas; the key setting does.)
  • Kubernetes auth: one ServiceAccount, one namespace, audience openbao, ttl/token_max_ttl/ token_explicit_max_ttl = 15m, token_no_default_policy: true, exactly one policy;
  • access_frontdoor.resolvable: false; agent_fence.data_and_metadata_denied: true (coding agents fenced);
  • admission names the standard and executor identity; full verification and lifecycle; explicit approval by every review.required_approvers role from approved onward.

Revert (restore-kv in the example) is a further next-version write of the prior value with CAS. Reading an older version is a read on data/<path>?version=N, which the policy already grants; no extra capability is needed.

What the role does not do. OpenBao does not evaluate the admission. The role is standing: a compromised nk-bind-executor ServiceAccount can replace the svc-authelia bind (sign-in outage on Authelia's next restart) but reach nothing else. The admission window, consume-once and plan digest are enforced by the executor, approval-engine and access-engine. If that is not enough, the founder can choose a window-scoped role instead (created by the attended platform-admin at the window start, removed after); that removes the "unattended" property of T06 for the platform side. Recommendation: standing role for the pilot, because the reachable damage is one read-only directory bind already covered by an attended recovery path (CCR-2026-0053 lifecycle.compromised).

Journey secrets (T10)

CCR-2026-0057 is attended-service-credential-delivery with runtime_access: false; its contract forbids any role or policy on that path. A workload-kv-read request for the executor therefore changes CCR-2026-0057's stated boundary. It must say so, cite CCR-2026-0057, and be approved by both platform-owner and net-kingdom-owner. CCR-2026-0057's attended procedure stays valid. Shape: role net-kingdom-bind-executor-syn-journey-read, policy read on the data path only, native login, 15m. Draft it when T10 is scheduled and the ServiceAccount exists.

Q2. Can the executor pod receive an ESO-projected audit-core sender bearer?

Yes, with the CCR-2026-0021/0022 shape, once audit-core admits the sender. The receipt is an event to audit-core; per RPF-WP-0067-T01 the wire is POST /v1/events to http://audit-core.audit-core.svc.cluster.local:8080, with a per-sender bearer from the registry at platform/workloads/audit-core/senders. Idempotency-Key is the envelope id and correlation_id is the run_id. The envelope source equals the sender name.

Shape (as docs/credential-lane-designs/factory-audit-senders-review.md):

  • custody platform/workloads/net-kingdom/bounded-executor/audit-sender (AUDIT_TOKEN), generated CAS=0 in the attended platform process and merged into the registry as one exact sender (proposed name nk-bounded-executor, tenant:platform, write true, read false, evidence_kind: load-bearing, secret_policy: redact); no existing sender changes;
  • exact-path policy, Kubernetes role for external-secrets/external-secrets only, ClusterSecretStore restricted to namespace sso; ExternalSecret into sso/nk-bind-executor-audit key audit-token, mounted as a file in the executor pod;
  • coding-agent fence on the new data and metadata paths.

The bearer lets the executor append its own receipts only. It is not an OpenBao identity. The ESO manifests belong in the rapp-* package, as in CCR-2026-0053, which points to net-kingdom bind-eso.yaml. Prerequisites: audit-core says yes to its Q1 (net-kingdom request §audit-core) and names the sender. Then a workload-kv-read CCR follows here.

Open items for the founder and other owners

  1. Review and approve or change CCR-2026-0058 (platform-owner, net-kingdom-owner). It stays proposed.
  2. Standing vs window-scoped write role (recommendation: standing for the pilot).
  3. Accept that a journey-read CCR widens CCR-2026-0057's runtime_access: false.
  4. secrets-engine: the LLDAP credential lane shape (its Q2) before a custody CCR can be drafted.
  5. audit-core: sender admission and name, before the sender CCR.
  6. railiance-apps / rapp package: the ServiceAccount sso/nk-bind-executor must exist before bound_claims_confirmed can be set.