railiance-platform/docs/credential-lane-designs/keycape-approval-client-side-readers.md
codex 32d5cf0211
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
Prepare the two approval client-side reader admissions
RPF-WP-0035-T06. Adds CCR-2026-0019 (secrets-engine) and CCR-2026-0020
(approval-engine-operator) with their exact-path read policies, reusing the
existing version-1 custody from the verifier activation. No reseed, rotation,
shared reader or verifier Secret reuse; both requests are in_flight and nothing
is applied.

The two shapes were decided by read-only survey rather than assumed.
secrets-engine consumes its client secret through an operator-run CLI reading a
protected file, and its namespace holds no workload, so reader 1 is an attended
operator-workstation OIDC lane rather than an ESO lane; its one missing input is
the operator group claim, which NetKingdom and KeyCape own. approval-engine is
not deployed and no owner source names who presents the operator client, so
reader 2 records the undetermined actor instead of guessing one for the widest
approval scope in the pair. Both declare openbao.auth missing rather than
carrying a placeholder binding.

T06 moves to wait on those two owner inputs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLUjpv3ssxNRAEPPgLFnEB

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1275505@bnt-lap001
Assistant-Session: 97265baa-f08f-4032-b290-a1e2965a69c5
2026-09-09 14:41:01 +02:00

79 lines
4.8 KiB
Markdown

# Approval client-side readers
RPF-WP-0035-T06, the residual handed over by the completed verifier custody
(T05). Requests:
[CCR-2026-0019](../../credential-change-requests/CCR-2026-0019-secrets-engine-approval-client-read.yaml)
and [CCR-2026-0020](../../credential-change-requests/CCR-2026-0020-approval-engine-operator-client-read.yaml).
Both are `in_flight`, neither is approved, and nothing is applied.
## Why this exists as separate requests
CCR-2026-0017/0018 admitted the **verifier** copies: KeyCape holds the two client
secrets so it can authenticate credentials presented to it. Presenting them is a
different power with a different holder, so it needs its own admission. The two
Warden fetch selectors that the verifier review left unresolved are exactly this
gap. Both readers use the **existing version-1 custody** — no reseed, no
rotation, no shared reader, no reuse of the `sso` verifier Secrets.
## Survey, 2026-09-09
Read-only, against owner source and the live cluster.
| Question | Finding |
| --- | --- |
| Is there an in-cluster secrets-engine consumer? | No. Namespace `secrets-engine` holds only ServiceAccount `secrets-engine` and no workload. `flex-auth/flex-auth-secrets-engine` is the flex-auth PDP for that consumer, not the service. |
| How does secrets-engine consume the client secret? | Operator-run CLI reading `SECRETS_ENGINE_APPROVAL_CLIENT_SECRET_FILE`, exchanged for a fresh token before each request, held in memory only, no refresh token or fallback identity. Implemented 2026-09-09, SECRETS-WP-0009-T03, `secrets-engine` revision `9eb07fd`. |
| Is approval-engine deployed? | No. No namespace, workload or Service. The owner manifest targets namespace `approval-engine` with a digest-pinned image and is unapplied. |
| Who presents `approval-engine-operator`? | Not identified by any owner source. approval-engine verifies these tokens and never presents them. |
## Reader 1 — secrets-engine-approval (CCR-2026-0019)
Shape is determined; one input is missing.
| Item | Value |
| --- | --- |
| Path / field | `platform/workloads/secrets-engine/approval-client` / `CLIENT_SECRET` |
| Policy | `workload-kv-read-secrets-engine-approval-client` (exact data + metadata read, written and committed) |
| Auth | `oidc` on mount `netkingdom`, role `secrets-engine-approval-client-read`, standard three redirect URIs, scopes `openid profile email groups`, `user_claim: sub`, `groups_claim: groups`, ttl 15m |
| Front door | `warden access secrets-engine-approval-client --out FILE` |
| Delivery | Protected owner-only file outside any Git work tree, consumed as `SECRETS_ENGINE_APPROVAL_CLIENT_SECRET_FILE`, removed at end of session |
**Missing:** the exact group claim for the authorized operator. NetKingdom and
KeyCape own it; this repo and secrets-engine cannot supply it. The role cannot
be created without it, so `openbao.auth` is declared missing rather than
recorded with a placeholder that would later be mistaken for a confirmed
binding.
This is an operator-workstation lane, not an External Secrets lane — because the
consumer is a CLI, not a pod. A file-delivered credential outlives the process
that read it, so removal depends on operator hygiene. That is weaker than the
pod-lifetime bound of the verifier delivery and is recorded as a consequence of
the consumer's shape rather than engineered away.
## Reader 2 — approval-engine-operator (CCR-2026-0020)
Held open deliberately. The exact-path read policy
`workload-kv-read-approval-engine-operator-client` is written and committed so
the eventual reader inherits a bounded grant rather than one drafted under time
pressure. Writing the policy is not admitting a reader.
**Missing:** the presenting actor and its placement. This client carries the
widest scope set in the pair — `approval:create`, `read`, `approve`, `revoke`,
`supersede`, `observe`, `emit`, and deliberately not `consume`. approval-engine
records `principal_type` on every entry rather than restricting who may supply
approver evidence, and its owner records that whether a non-human principal
*should* is approval doctrine belonging to `gate-house`. Naming a reader here
would hand the widest approval scope to a guessed identity, so the request names
what is undetermined instead.
The delivery surface follows the actor: an attended operator implies a protected
workstation file; an in-cluster component implies an ExternalSecret into the
eventual `approval-engine` namespace; an agent surface implies neither.
## Not in scope
- No reseed or rotation of either custody path. Rotation is one version-guarded
operation shared with the verifier copies and needs both owners.
- No `approval:consume` on the operator client, now or by later scope edit.
- No reuse of the `sso` verifier Secrets or the KeyCape verifier roles.
- No audit-sender custody; that stays with the existing owner records.