id: CCR-2026-0018 kind: credential-change-request schema_version: 1 request_type: workload-kv-read title: KeyCape verifier custody for the approval-engine-operator confidential client status: proposed created: '2026-09-08' updated: '2026-09-08' requester: agent: claude reason: >- Second of the two registrations in KEY-WP-0013-T02 (State Hub message 278a3ebe-b529-49f6-bd1a-e3ebcf318260): client approval-engine-operator, subject service:approval-engine-operator, audience approval-engine, tenant:platform per resolved decision 5ed3fb35-eca9-413a-82b9-95171ba85bf6, 15m token lifetime. Scopes are approval:create, read, approve, revoke, supersede, observe and emit, explicitly without approval:consume. KeyCape owns registration and issuance; this request establishes only custody and the KeyCape-side delivery. review: required: true required_approvers: - platform-operator - key-cape-owner comments: - at: '2026-09-08' reviewer: railiance-platform (codex/claude) decision: paths_confirmed_field_corrected comment: >- KV path platform/workloads/approval-engine/operator-client is confirmed unchanged and conforms to the platform/workloads// convention. Field client_secret is corrected to CLIENT_SECRET for the same uppercase convention and validator constraint as CCR-2026-0017. Kubernetes Secret sso/keycape-approval-engine-operator-client with key client-secret and the KeyCape environment name are confirmed as proposed. target: domain: financials tenant: platform workload: approval-engine environment: production purpose: >- Hold the approval-engine-operator confidential client secret in platform custody and project it into the KeyCape runtime so KeyCape can verify presented client_credentials for the operator client. openbao: mount: platform kv_path: platform/workloads/approval-engine/operator-client fields: - CLIENT_SECRET policy_name: workload-kv-read-keycape-approval-engine-operator policy_file: openbao/policies/workload-kv-read-keycape-approval-engine-operator.hcl auth: method: kubernetes mount: kubernetes role: external-secrets-keycape-approval-engine-operator bound_claims: service_account_names: - external-secrets service_account_namespaces: - external-secrets bound_claims_confirmed: true policies: - workload-kv-read-keycape-approval-engine-operator ttl: 15m access_frontdoor: type: ops-warden catalog_id: keycape-approval-engine-operator-client selector: KeyCape approval-engine-operator confidential client secret command: warden access keycape-approval-engine-operator-client --fetch CLIENT_SECRET resolvable: false readiness: pending-review delivery: surface: external-secrets target: >- ClusterSecretStore openbao-keycape-approval-engine-operator, limited to namespace sso, to ExternalSecret sso/keycape-approval-engine-operator-client and Secret sso/keycape-approval-engine-operator-client with key client-secret. KeyCape resolves it as KEYCAPE_APPROVAL_ENGINE_OPERATOR_CLIENT_SECRET through a secretKeyRef. Manifests: argocd/platform-addons/openbao-secretstore/openbao-keycape-approval-clients.clustersecretstore.yaml and keycape-approval-clients.externalsecrets.yaml. risk: classification: high notes: - >- This client carries the widest approval scope set in the pair — create, approve, revoke and supersede. A leak allows forging approval lifecycle actions, which is a stronger outcome than the read/consume client in CCR-2026-0017. - >- The absence of approval:consume is a deliberate separation of duties. Any later request to add consume to this client is a new lane decision, not a scope edit. - >- Kept on its own policy, role and store so it can be revoked independently of the secrets-engine-approval client. - >- Compromise response is KeyCape disabling the registration plus rotation of this KV version; approval actions already emitted are not retracted by rotation and need approval-engine's own audit review. verification: positive: - >- The ExternalSecret in namespace sso syncs CLIENT_SECRET to Secret key client-secret without printing the value. - >- The KeyCape build issues a token for subject service:approval-engine-operator with audience approval-engine, tenant:platform and 15m lifetime, verified against live JWKS signature. negative: - >- A namespace outside the approved ClusterSecretStore condition cannot use this store to read the path. - >- A service account outside external-secrets/external-secrets cannot authenticate through role external-secrets-keycape-approval-engine-operator. - >- The role cannot read the sibling secrets-engine approval-client path, any parent listing, or any other platform workload path. - >- The operator client is denied approval:consume, and denial is observed rather than assumed. activation_conditions: - >- Same single attended rollout window and prepared-but-undeployed KeyCape image as CCR-2026-0017; see docs/credential-lane-designs/keycape-approval-clients.md. - >- Attended first provision only through openbao-platform-admin-login (founder_required, attended OIDC via netkingdom role=platform-admin) with a unique receipt path. - >- Policy, Kubernetes auth role and ClusterSecretStore applied before the ExternalSecret; sync confirmed before the KeyCape rollout. - Positive and negative results recorded with non-secret request ids or timestamps. evidence: [] lifecycle: deactivate: >- KeyCape disables the approval-engine-operator registration; platform detaches the policy from role external-secrets-keycape-approval-engine-operator and removes the ExternalSecret. rotate: >- KeyCape mints a replacement client secret; platform writes the new KV version under the same attended authority. Rotation is independent of CCR-2026-0017. compromised: >- Disable the registration at KeyCape, rotate the KV version, and refer emitted approval actions to approval-engine for audit review. state_hub: workplan_id: RPF-WP-0035 task_id: RPF-WP-0035-T05 related_message: 278a3ebe-b529-49f6-bd1a-e3ebcf318260 related_decision: 5ed3fb35-eca9-413a-82b9-95171ba85bf6