From 3c69a25442aefa9d008e1a938db7374141abed9d Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 31 Oct 2026 23:02:47 +0100 Subject: [PATCH] MASON-WP-0010-T01: review oidc-service-client 0.1 materialization (acceptable with changes) Eleven findings (R1-R11) on net-kingdom's proposed SecurityCaseType oidc-service-client 0.1 for request f61cc81e: type changes R3, R4, R6, R7, R8; ops-mason builder follow-ups R10; rollback addition R11. Co-Authored-By: Claude Opus 5.5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 5502@bnt-lap001 Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196 --- ...N-WP-0010-security-case-materialization.md | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/workplans/MASON-WP-0010-security-case-materialization.md b/workplans/MASON-WP-0010-security-case-materialization.md index 1a9880c..cb2f132 100644 --- a/workplans/MASON-WP-0010-security-case-materialization.md +++ b/workplans/MASON-WP-0010-security-case-materialization.md @@ -9,7 +9,7 @@ flavor: implementation owner: claude-code topic_slug: netkingdom created: "2026-10-08" -updated: "2026-10-11" +updated: "2026-10-31" depends_on: [] related_repos: - net-kingdom @@ -98,6 +98,111 @@ NK-WP-0048-T05 still waits on WARDEN-WP-0044-T01 and a founder answer. 2026-10-09: the founder accepted memo r4; hub decision `e418263e` resolved and the type is `acknowledged` (net-kingdom `0e86f95`). T02 is unblocked. +**Review (2026-10-31) of net-kingdom `security-case-types/oidc-service-client/type.yaml` 0.1** +(proposed, net-kingdom `5d5f15d`, memo `nk-wp-0056-t14-oidc-service-client-r1`, +hub decision `f8044f81`, request message `f61cc81e`). Checked against the +browser type 1.1, the live CCR-2026-0041/0042 placement and the bounded +executor's native lanes CCR-2026-0058/0059, and by a trial render of +`examples/nk-bind-executor-approval.yaml` through `case_plan.render` and +`case_build` on a scratch copy marked `acknowledged` (no live survey, no +OpenBao). All six items render; names come out as +`workload-kv-read-keycape-nk-bind-executor-approval-{eso,bounded-executor}`, +`external-secrets-keycape-nk-bind-executor-approval` and catalog entry +`bounded-executor-keycape-nk-bind-executor-approval`. + +Verdict: **acceptable with changes.** The structure is right and reuses the +browser type's custody, ESO and policy families. R3, R4, R6, R7 and R8 change +the type (so memo r2 replaces r1); R10 is ops-mason's own builder work and does +not block acknowledgment, but must land before the first case is built. + +- **R1 — client-secret-path: ok.** Derived, not case-settable, same + `platform/workloads/keycape/{client_id}` / `CLIENT_SECRET` as the browser type + and CCR-2026-0033. Unconditional (the type is always confidential), so no + `when`. `client_id` is unique in KeyCape, so browser and service clients + cannot collide in the one `keycape/` subtree. +- **R2 — keycape-reader-policy and naming family: ok.** Unchanged from the + browser type; `workload-kv-read-keycape--` is respected for + both readers. Longest rendered name is 68 characters, within OpenBao limits. +- **R3 — eso-role: change needed (small).** Bound to + `external-secrets/external-secrets`, one policy, 15m, no default policy: + right. But the body omits `audience: openbao` and `token_explicit_max_ttl: + 15m`, which the consumer role states and the live + `external-secrets-keycape-forgejo` role has; ops-mason's builder fills them + in silently today. Add both so the template is what gets built, and the two + roles read the same. +- **R4 — consumer-reader-policy self-lifecycle stanzas: change needed.** The + `auth/token/lookup-self` (read) and `auth/token/revoke-self` (update) stanzas + are correct and needed (a native per-call reader should revoke its token + after the read, and the platform applier refuses a `token_self_lifecycle: + true` policy without them, see T04 2026-10-10). But only the consumer policy + declares them, while the ESO policy needs them equally. Declare them in + **both** policy bodies, so each body is the complete policy the review + checks (item 3 of the 1.0 review). ops-mason then stops appending them (R10). +- **R5 — consumer-reader-role (native Kubernetes auth): ok.** One + ServiceAccount, one namespace, audience `openbao`, 15m ttl/max/explicit max, + one policy, no default policy: this is exactly the CCR-2026-0058/0059 shape + that is live and verified for `sso/nk-bind-executor`, and "policies are never + combined in one role" holds (the executor gets a third separate role). Role + name equal to the policy name matches the native-lane convention. Dropping + ESO delivery to the consumer removes a Secret copy and a SecretStore per + case; ops-mason prefers it. +- **R6 — consumer binding parameters: change needed.** The patterns admit + `consumer_service_account: default` and namespaces such as + `external-secrets`, `openbao` or `kube-system`. Refuse `default` (any pod in + the namespace would read the client secret; CCR-2026-0059 verifies the + default SA is denied), and refuse the `external-secrets` and `openbao` + namespaces, in the type's constraints or the validator. +- **R7 — shared namespace with KeyCape's copy: change needed.** The first case + binds `sso/nk-bind-executor`, and `sso` is where `deliver-secret` writes + `keycape-{client_id}-client`. So "no Secret copy in the consumer's namespace" + (README, purpose) is false for this case; isolation rests on the consumer SA + having no Secret read in its namespace (true today: rapp-bounded-executor + `manifests/rbac.yaml` grants no Secret access). Add a verification: + `{consumer_namespace}/{consumer_service_account}` cannot get Secrets in its + namespace (in particular `sso/keycape-{client_id}-client`), `can-i` denial as + proof; and reword the README claim to "the type creates no Secret copy for + the consumer". +- **R8 — verification wording: change needed (small).** + `custody-allowed-to-consumer` says the policy grants read on the path "and + nothing else"; with R4 it also grants token self-lookup/revoke. Say "and no + other path under `platform/`, apart from token self-lifecycle". Optionally + add the same allow check for the ESO policy. +- **R9 — catalog-entry: ok, one question.** `{consuming_service}-keycape-{client_id}` + instead of the browser type's `{consuming_service}-keycape-client` is right: + a service holds one client per audience, so the browser form would collide. + Question: `consuming_service: bounded-executor` differs from the workload name + the platform already uses for this executor (`net-kingdom-bind-executor` in + CCR-2026-0058/0059 and their catalog ids). The case should use the + established name, or the type README should say which one `workload_ref` + carries. +- **R10 — ops-mason builder (ours, not a type change).** The trial build shows + four defects to fix before the first service-client case is built: + (a) `_policy_hcl` always appends the self-lifecycle stanzas, so the consumer + policy gets them twice; append only when absent. (b) A policy with a role is + treated as ESO: the consumer CCR gets `access_frontdoor.type: + external-secrets`; for a native role it must be `platform-owner` (as + CCR-2026-0059) with a `delivery: {surface: native-workload-login, namespace, + service_account}` block. (c) `catalog_id` is hard-coded to + `{consuming_service}-keycape-client`; take it from the catalog item. + (d) `audience` and `token_explicit_max_ttl` are hard-coded / copied from + `token_max_ttl`; take them from the role body (with R3). The consumer CCR is + no longer `in_flight`: with the role in the type it is complete `proposed`, + `bound_claims_confirmed: false` until the platform owner confirms the SA. +- **R11 — rollback order: ok, with one addition.** Consumer configuration, + registration, env binding, delivery, then custody (one metadata delete, after + the ExternalSecret is gone, per item 6 of the 1.0 review), roles before their + policies, catalog last: consistent with the browser type. Addition: deleting + the consumer role does not revoke issued tokens; state that rollback is + complete only after the consumer's last token has expired (at most 15m after + the role is deleted) or was revoked, as the T03 deactivate note does. + Suggested, not required: remove `consumer-reader-role` directly after + `hand-over` is reversed, so consumer access ends first. (ops-mason's own + `rollback.yaml` lists `removes_exactly` in plain reverse order, which differs + from the type's steps; fixed with R10.) + +T04 is unchanged by this type: `secrets-engine-openbao`'s second reader is an +attended OIDC operator, not a ServiceAccount, so it fits neither type. + ```task id: MASON-WP-0010-T02 status: done