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
107 lines
7.7 KiB
Markdown
107 lines
7.7 KiB
Markdown
# 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.
|