RPF-WP-0069: answer NK-WP-0056-T02; add workload-kv-write-next-version; CCR-2026-0058 (proposed)
Owner answer for the bounded executor (hub 9d08288d): one Kubernetes role per lane for sso/nk-bind-executor; new contract-only request type for a CAS next-version write (no create, metadata or delete, 15m, agents fenced); CCR-2026-0058 drafted as proposed, not approved; audit sender in the CCR-2026-0021/0022 shape once audit-core admits it. 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
This commit is contained in:
parent
c5f9770c97
commit
8b57d270de
8 changed files with 553 additions and 0 deletions
107
docs/credential-lane-designs/bounded-executor.md
Normal file
107
docs/credential-lane-designs/bounded-executor.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# 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, `required_parameters = ["options"]`,
|
||||
`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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue