# 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/.hcl`): `read` + `update` on `platform/data/` 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/?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.