diff --git a/argocd/platform-addons/openbao-secretstore/t03-requester.yaml b/argocd/platform-addons/openbao-secretstore/t03-requester.yaml new file mode 100644 index 0000000..6649864 --- /dev/null +++ b/argocd/platform-addons/openbao-secretstore/t03-requester.yaml @@ -0,0 +1,44 @@ +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: openbao-keycape-secrets-engine-requester + labels: + app.kubernetes.io/part-of: railiance-gitops + railiance-platform/component: external-secrets + app.kubernetes.io/name: keycape +spec: + provider: + vault: + server: http://openbao.openbao.svc:8200 + path: platform + version: v2 + auth: + kubernetes: + mountPath: kubernetes + role: external-secrets-keycape-secrets-engine-requester + serviceAccountRef: + name: external-secrets + namespace: external-secrets + conditions: + - namespaces: + - sso +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: keycape-secrets-engine-requester-client + namespace: sso +spec: + refreshInterval: 5m + secretStoreRef: + kind: ClusterSecretStore + name: openbao-keycape-secrets-engine-requester + target: + name: keycape-secrets-engine-requester-client + creationPolicy: Owner + deletionPolicy: Retain + data: + - secretKey: client-secret + remoteRef: + key: workloads/secrets-engine/approval-requester + property: CLIENT_SECRET diff --git a/credential-change-requests/CCR-2026-0024-t03-requester-verifier.yaml b/credential-change-requests/CCR-2026-0024-t03-requester-verifier.yaml new file mode 100644 index 0000000..2a9a249 --- /dev/null +++ b/credential-change-requests/CCR-2026-0024-t03-requester-verifier.yaml @@ -0,0 +1,105 @@ +id: CCR-2026-0024 +kind: credential-change-request +schema_version: 1 +request_type: workload-kv-read +title: T03 create-only requester KeyCape verifier custody +status: applied +created: '2026-09-14' +updated: '2026-09-14' +requester: + agent: codex + reason: User instructed completion of SECRETS-WP-0010-T03 and explicitly confirmed + its scoped human review mandate. A separate create-only requester is required; + the withdrawn combined operator client remains unused. +review: + required: true + required_approvers: + - platform-operator + - key-cape-owner + comments: + - at: '2026-09-14' + reviewer: operator instruction in Codex session + decision: approved + comment: Necessary implementation of the user-authorized T03 completion. Exact + requester has only approval:create, subject secrets-engine matching the existing + evaluator actor, audience approval-engine, tenant:platform, lifetime 15m. No + approval, consume, provider-key access or model-spending scope. Separate reader + and verifier remain exact to this new path; no old credential or registration + is widened. +target: + domain: financials + tenant: platform + workload: secrets-engine + environment: production + purpose: T03 create-only requester KeyCape verifier custody; execute only the three + fixed T03 request records. +openbao: + mount: platform + kv_path: platform/workloads/secrets-engine/approval-requester + fields: + - CLIENT_SECRET + policy_name: workload-kv-read-keycape-secrets-engine-requester + policy_file: openbao/policies/workload-kv-read-keycape-secrets-engine-requester.hcl + auth: + method: kubernetes + mount: kubernetes + role: external-secrets-keycape-secrets-engine-requester + bound_claims: + service_account_names: + - external-secrets + service_account_namespaces: + - external-secrets + bound_claims_confirmed: true + policies: + - workload-kv-read-keycape-secrets-engine-requester + ttl: 15m +access_frontdoor: + type: ops-warden + catalog_id: secrets-engine-requester-login + selector: T03 create-only approval requester + command: warden access secrets-engine-requester-login --exec -- + resolvable: false + readiness: pending-review +delivery: + surface: external-secrets + target: sso/keycape-secrets-engine-requester-client via ESO; env KEYCAPE_SECRETS_ENGINE_REQUESTER_CLIENT_SECRET +risk: + classification: high + notes: + - Credential authenticates only the separate approval:create requester. Human disposition + remains mandatory and uses a different public PKCE client. + - The stable subject secrets-engine matches the existing evaluator and Approval + Engine binding.actor check; it is not an alias for consumer subject service:secrets-engine. +verification: + positive: + - Exact scope and 900-second token lifetime; native create of only the reviewed + three records. + negative: + - Approval and consume scopes refused; sibling KV paths and parent listing denied. + activation_conditions: + - Attended platform authority, CAS=0 custody, exact policy/auth readback and synchronized + verifier delivery. + - Separate reader verification and no human entry synthesized. + evidence: + - at: '2026-09-14T00:23:31+00:00' + actor: operator via attended T03 requester custody session + kind: delegated_metadata_apply + result: passed + details: + - Delegated metadata applier ran as operator via attended T03 requester custody + session using local bao CLI ambient authority. + - 'Policy metadata write: sys/policies/acl/workload-kv-read-keycape-secrets-engine-requester' + - 'Auth role metadata write: auth/kubernetes/role/external-secrets-keycape-secrets-engine-requester' + - No secret values were read, written, printed, or accepted in argv. +lifecycle: + deactivate: Disable the secrets-engine-requester KeyCape registration and detach + only the two requester reader roles. Preserve approvals and existing consumer/verifier + lanes. + rotate: Rotate through KeyCape and platform using a new version with predecessor + refusal proof. + compromised: Disable requester issuance first; revoke sessions and rotate under + attended owner authority. +state_hub: + workplan_id: RPF-WP-0035 + task_id: RPF-WP-0035-T06 + related_request: CCR-2026-0025 diff --git a/credential-change-requests/CCR-2026-0025-t03-requester-reader.yaml b/credential-change-requests/CCR-2026-0025-t03-requester-reader.yaml new file mode 100644 index 0000000..b170351 --- /dev/null +++ b/credential-change-requests/CCR-2026-0025-t03-requester-reader.yaml @@ -0,0 +1,115 @@ +id: CCR-2026-0025 +kind: credential-change-request +schema_version: 1 +request_type: workload-kv-read +title: T03 create-only requester attended operator reader +status: applied +created: '2026-09-14' +updated: '2026-09-14' +requester: + agent: codex + reason: User instructed completion of SECRETS-WP-0010-T03 and explicitly confirmed + its scoped human review mandate. A separate create-only requester is required; + the withdrawn combined operator client remains unused. +review: + required: true + required_approvers: + - platform-operator + - secrets-engine-owner + comments: + - at: '2026-09-14' + reviewer: operator instruction in Codex session + decision: approved + comment: Necessary implementation of the user-authorized T03 completion. Exact + requester has only approval:create, subject secrets-engine matching the existing + evaluator actor, audience approval-engine, tenant:platform, lifetime 15m. No + approval, consume, provider-key access or model-spending scope. Separate reader + and verifier remain exact to this new path; no old credential or registration + is widened. +target: + domain: financials + tenant: platform + workload: secrets-engine + environment: production + purpose: T03 create-only requester attended operator reader; execute only the three + fixed T03 request records. +openbao: + mount: platform + kv_path: platform/workloads/secrets-engine/approval-requester + fields: + - CLIENT_SECRET + policy_name: workload-kv-read-secrets-engine-requester-client + policy_file: openbao/policies/workload-kv-read-secrets-engine-requester-client.hcl + auth: + method: oidc + mount: netkingdom + role: secrets-engine-requester-workload-kv-read + allowed_redirect_uris: + - https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback + - http://localhost:8250/oidc/callback + - http://127.0.0.1:8250/oidc/callback + oidc_scopes: + - openid + - profile + - email + - groups + user_claim: sub + groups_claim: groups + bound_claims: + groups: + - net-kingdom-admins + bound_claims_confirmed: true + policies: + - workload-kv-read-secrets-engine-requester-client + ttl: 15m +access_frontdoor: + type: ops-warden + catalog_id: secrets-engine-requester-login + selector: T03 create-only approval requester + command: warden access secrets-engine-requester-login --exec -- + resolvable: false + readiness: pending-review +delivery: + surface: operator-workstation + target: Contained attended reader session; secret stays in memory for native requester + exchange; no retained file or raw output. +risk: + classification: high + notes: + - Credential authenticates only the separate approval:create requester. Human disposition + remains mandatory and uses a different public PKCE client. + - The stable subject secrets-engine matches the existing evaluator and Approval + Engine binding.actor check; it is not an alias for consumer subject service:secrets-engine. +verification: + positive: + - Exact scope and 900-second token lifetime; native create of only the reviewed + three records. + negative: + - Approval and consume scopes refused; sibling KV paths and parent listing denied. + activation_conditions: + - Attended platform authority, CAS=0 custody, exact policy/auth readback and synchronized + verifier delivery. + - Separate reader verification and no human entry synthesized. + evidence: + - at: '2026-09-14T00:23:32+00:00' + actor: operator via attended T03 requester custody session + kind: delegated_metadata_apply + result: passed + details: + - Delegated metadata applier ran as operator via attended T03 requester custody + session using local bao CLI ambient authority. + - 'Policy metadata write: sys/policies/acl/workload-kv-read-secrets-engine-requester-client' + - 'Auth role metadata write: auth/netkingdom/role/secrets-engine-requester-workload-kv-read' + - No secret values were read, written, printed, or accepted in argv. +lifecycle: + deactivate: Disable the secrets-engine-requester KeyCape registration and detach + only the two requester reader roles. Preserve approvals and existing consumer/verifier + lanes. + rotate: Rotate through KeyCape and platform using a new version with predecessor + refusal proof. + compromised: Disable requester issuance first; revoke sessions and rotate under + attended owner authority. +state_hub: + workplan_id: RPF-WP-0035 + task_id: RPF-WP-0035-T06 + related_request: CCR-2026-0024 diff --git a/docs/evidence/2026-09-14-t03-native-approval-requests.json b/docs/evidence/2026-09-14-t03-native-approval-requests.json new file mode 100644 index 0000000..bf87b72 --- /dev/null +++ b/docs/evidence/2026-09-14-t03-native-approval-requests.json @@ -0,0 +1,145 @@ +{ + "observed_at": "2026-09-14T00:33:04.552946+00:00", + "status": "created", + "phase": "three_unapproved_requests_created", + "requests": [ + { + "memo_id": "SECRETS-WP-0010-T03-apply", + "action": "apply", + "approval": { + "binding": { + "action": "apply", + "actor": "secrets-engine", + "digest": "sha256:03cc5b37437f14e86b686ce4054f976556334eff3fa260b03e8014ed3d9217e5", + "human_control": true, + "pdp_digest": "sha256:933427642c58c54f65dd4781b8e4c8e2f358eb96497ae35870fff4bd593d2b84", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-openrouter-llm-connect" + ], + "fields": [], + "policy_targets": [ + "se-prod-openrouter-llm-connect" + ], + "stage": "prod" + }, + "id": "catalog:openrouter-llm-connect", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-14T00:33:07+00:00", + "entries": [], + "id": "09592588-ab15-53e7-89b8-c4e9f29aaacf", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-14T00:33:07+00:00", + "validity": { + "expires_at": "2026-09-15T00:33:06.559689+00:00", + "not_before": "2026-09-14T00:33:06.559689+00:00" + } + } + }, + { + "memo_id": "SECRETS-WP-0010-T03-verify", + "action": "verify", + "approval": { + "binding": { + "action": "verify", + "actor": "secrets-engine", + "digest": "sha256:72d9267d038c17107c880ffc9009793ce9c70defbddfe2219628854b811a04b2", + "human_control": true, + "pdp_digest": "sha256:9e36cdbf3890cc5a7e550fd57191f9c0f2a6b2180909aac302aa3b999e7e6b25", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-openrouter-llm-connect" + ], + "fields": [ + "OPENROUTER_API_KEY" + ], + "policy_targets": [ + "se-prod-openrouter-llm-connect" + ], + "stage": "prod" + }, + "id": "catalog:openrouter-llm-connect", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-14T00:33:07+00:00", + "entries": [], + "id": "9416fa31-fa9e-5603-8289-f35bc9625409", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-14T00:33:07+00:00", + "validity": { + "expires_at": "2026-09-15T00:33:06.722887+00:00", + "not_before": "2026-09-14T00:33:06.722887+00:00" + } + } + }, + { + "memo_id": "SECRETS-WP-0010-T03-exec", + "action": "exec", + "approval": { + "binding": { + "action": "exec", + "actor": "secrets-engine", + "digest": "sha256:f2cf0fb53b740900756ccde5587c3578fcff44beef2f1edab17b9a198a4033d8", + "human_control": true, + "pdp_digest": "sha256:9f17812750fc8962b0fc58fc09df136850c9935a864fafa998a1c030dfb75bd9", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-openrouter-llm-connect" + ], + "fields": [ + "OPENROUTER_API_KEY" + ], + "policy_targets": [ + "se-prod-openrouter-llm-connect" + ], + "stage": "prod" + }, + "id": "catalog:openrouter-llm-connect", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-14T00:33:07+00:00", + "entries": [], + "id": "da678b61-35be-598e-8d95-a7aefa2fdc73", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-14T00:33:07+00:00", + "validity": { + "expires_at": "2026-09-15T00:33:06.955168+00:00", + "not_before": "2026-09-14T00:33:06.955168+00:00" + } + } + } + ], + "credential_values_emitted": false, + "signature_verified": true, + "excess_scopes_refused": true, + "wrong_secret_refused": true, + "reader_scope_verified": true, + "human_entries_created": false, + "approvals_consumed": false, + "warden_session": "exited_0_after_self_revocation_and_helper_cleanup" +} diff --git a/docs/evidence/2026-09-14-t03-requester-provision.json b/docs/evidence/2026-09-14-t03-requester-provision.json new file mode 100644 index 0000000..35b5d2f --- /dev/null +++ b/docs/evidence/2026-09-14-t03-requester-provision.json @@ -0,0 +1,24 @@ +{ + "observed_at": "2026-09-14T00:23:24.931083+00:00", + "status": "applied", + "phase": "keycape_ready", + "ccrs": [ + "CCR-2026-0024", + "CCR-2026-0025" + ], + "credential_values_emitted": false, + "approval_mutations": false, + "kv_version": 1, + "request_id": "2f85087b-68af-028a-a9a7-3c0d89c06c03", + "keycape": { + "deployment_uid": "99ddd83c-cb3f-4847-bcf8-35f1aa87627f", + "generation": 51, + "pod_uid": "c4b4b63c-fd5b-45eb-bfa5-59197afe1412", + "single_ready_replica": true + }, + "image_unchanged": "forgejo.coulomb.social/coulomb/key-cape@sha256:db2c5a13a47839049349e881c8d19bc39f720ee69d8518f9f2eba2b1f98af9d5", + "unrelated_config_preserved": true, + "verifier_secret_exported": false, + "requester_credential_presented": false, + "warden_session": "exited_0_after_self_revocation_and_helper_cleanup" +} diff --git a/openbao/policies/workload-kv-read-keycape-secrets-engine-requester.hcl b/openbao/policies/workload-kv-read-keycape-secrets-engine-requester.hcl new file mode 100644 index 0000000..4daa40b --- /dev/null +++ b/openbao/policies/workload-kv-read-keycape-secrets-engine-requester.hcl @@ -0,0 +1,7 @@ +path "platform/data/workloads/secrets-engine/approval-requester" { + capabilities = ["read"] +} + +path "platform/metadata/workloads/secrets-engine/approval-requester" { + capabilities = ["read"] +} diff --git a/openbao/policies/workload-kv-read-secrets-engine-requester-client.hcl b/openbao/policies/workload-kv-read-secrets-engine-requester-client.hcl new file mode 100644 index 0000000..4daa40b --- /dev/null +++ b/openbao/policies/workload-kv-read-secrets-engine-requester-client.hcl @@ -0,0 +1,7 @@ +path "platform/data/workloads/secrets-engine/approval-requester" { + capabilities = ["read"] +} + +path "platform/metadata/workloads/secrets-engine/approval-requester" { + capabilities = ["read"] +} diff --git a/scripts/create-t03-approval-requests.py b/scripts/create-t03-approval-requests.py new file mode 100644 index 0000000..c894070 --- /dev/null +++ b/scripts/create-t03-approval-requests.py @@ -0,0 +1,93 @@ +"""Silent, single-attempt creation of the three operator-reviewed T03 requests.""" +import base64,json,os,stat,subprocess,time +from pathlib import Path +from datetime import datetime,timezone,timedelta +from urllib.request import Request,build_opener,ProxyHandler,HTTPRedirectHandler +from urllib.parse import urlencode +from urllib.error import HTTPError +import jwt +ROOT=Path('/home/worsch/railiance-platform') +RECEIPT=ROOT/'docs/evidence/2026-09-14-t03-native-approval-requests.json' +POLICY='workload-kv-read-secrets-engine-requester-client' +KV='platform/data/workloads/secrets-engine/approval-requester' +ISSUER='https://kc.coulomb.social' +class NoRedirect(HTTPRedirectHandler): + def redirect_request(self,*args,**kwargs): return None + +def http(url,*,body=None,headers=None): + req=Request(url,data=body,headers=headers or {}) + try: + with build_opener(ProxyHandler({}),NoRedirect()).open(req,timeout=20) as response: + content=response.read(1048577);status=response.status + except HTTPError as error: + status=error.code;content=error.read(1048577);error.close() + if len(content)>1048576:raise ValueError('response_too_large') + return status,json.loads(content) + +def bao(*args): + p=subprocess.run(['bao',*args],capture_output=True,text=True,timeout=20) + if p.returncode:raise ValueError('metadata_failed') + return json.loads(p.stdout) + +def check_identity(d): + policies=set(d.get('policies',[]))|set(d.get('identity_policies',[])) + if POLICY not in policies or policies-{POLICY,'default'} or not d.get('entity_id') or not 0 validated PDP Check -> CAS consume separately for apply, +verify and exec using scoped attended authority, and capture native denial, +revocation, workload health and key-check evidence. No OpenRouter credential has +been read and no inference or spend was performed. T03 remains waiting; this +entry supersedes earlier statements that requester or group admission is missing.