NK-WP-0054-T04: KeyCape live view compared; rapp-qonto-client declared by its live name
All checks were successful
Bounded-execution contracts / contracts (push) Successful in 2m46s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 149903@bnt-lap001
Assistant-Session: 4c20a536-1452-4a85-bc09-e1987d9817d6
This commit is contained in:
tegwick 2026-11-07 19:12:49 +01:00
parent 6252ab8d7e
commit ff7e295fd0
4 changed files with 405 additions and 4 deletions

View file

@ -78,3 +78,28 @@ The founder re-exported with the RPF-WP-0067-T03 commands. Both exited 0, and no
The executor's write role `net-kingdom-bind-executor-svc-authelia-write` is absent, which CCR-2026-0058 requires
between admitted runs. The checker now treats that absence as conformant (`window_scoped`).
## KeyCape live view, 2026-11-07 (KEY-WP-0045-T02)
The founder ran `keycape identity-facts` on the deployed `sso/keycape-config`, streamed without writing the config
to disk. Output: `keycape-identity-facts-20261107.json`, sha256 `755ab2c27be251e0db6ebef8e2754734c584e920070b23d939dc6b4e3b9087cd`. It holds no secret-shaped values, and
KeyCape's own `findings` list is empty.
**Matches the declaration:**
- the service clients `approval-engine-operator`, `informed-decision-sitting-requester` (now including
`approval:read`, so the 2026-10-31 live step is in place), `secrets-engine-approval`, `secrets-engine-openbao`
and `secrets-engine-requester`, all with exactly the declared scopes;
- the directory bind `svc-keycape`, which is not a directory admin (T05 split live);
- the factor service with `require_for_all: true`.
**Items for key-cape:**
1. `approval-engine-operator` is still registered with `approval:approve`. The declaration noted it as withdrawn
(KEY-WP-0013-T02). A service client that can approve conflicts with GH-DEC-2026-026: a service relies on an
approval and must never be one of its approvers.
2. `upstream_oidc.client_secret` is `inline`: the Authelia client secret sits in the config instead of an env
reference.
3. The declared `rapp-qonto` is live as `rapp-qonto-client` (`qonto:read`, role `qonto-reader`). That resolves its
`unknown`; the declaration needs the live name.
The human public clients and `nk-bind-executor-approval` are covered elsewhere (relying parties;
`bounded-executor.yaml`). `observe.py` does not yet compare KeyCape automatically.

View file

@ -0,0 +1,369 @@
{
"schema": "keycape-identity-facts/v0.1",
"issuer": "https://kc.coulomb.social",
"environment": "production",
"token_lifetime": "15m",
"clients": [
{
"client_id": "approval-engine-operator",
"principal_type": "SERVICE",
"client_type": "confidential",
"grant_types": [
"client_credentials"
],
"audience": "approval-engine",
"audience_source": "registration",
"scopes": [
"approval:create",
"approval:read",
"approval:approve",
"approval:revoke",
"approval:supersede",
"approval:observe",
"approval:emit"
],
"service_subject": "service:approval-engine-operator",
"tenant": "tenant:platform",
"roles": [
"approval-operator"
],
"token_lifetime": "15m",
"credential": "env-ref"
},
{
"client_id": "coulomb-social",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "coulomb-social",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"email",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"mfa_required": false,
"credential": "none"
},
{
"client_id": "demo-app",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "demo-app",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"email",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"credential": "none"
},
{
"client_id": "forgejo",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "forgejo",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"email",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"mfa_required": true,
"credential": "none"
},
{
"client_id": "informed-decision-approver",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "approval-engine",
"audience_source": "registration",
"scopes": [
"openid",
"approval:read",
"approval:approve"
],
"tenant": "tenant:platform",
"roles": [],
"token_lifetime": "15m",
"mfa_required": true,
"credential": "none"
},
{
"client_id": "informed-decision-sitting-requester",
"principal_type": "SERVICE",
"client_type": "confidential",
"grant_types": [
"client_credentials"
],
"audience": "approval-engine",
"audience_source": "registration",
"scopes": [
"approval:create",
"approval:read"
],
"service_subject": "informed-decision",
"tenant": "tenant:platform",
"roles": [
"informed-decision-sitting-requester"
],
"token_lifetime": "15m",
"credential": "env-ref"
},
{
"client_id": "netkingdom-bootstrap-console",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "netkingdom-bootstrap-console",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"email",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"credential": "none"
},
{
"client_id": "nk-bind-executor-approval",
"principal_type": "SERVICE",
"client_type": "confidential",
"grant_types": [
"client_credentials"
],
"audience": "approval-engine",
"audience_source": "registration",
"scopes": [
"approval:create",
"approval:read",
"approval:consume"
],
"service_subject": "service:nk-bind-executor",
"tenant": "tenant:platform",
"roles": [
"bounded-executor"
],
"token_lifetime": "15m",
"credential": "env-ref"
},
{
"client_id": "nk-synthetic-journey",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "nk-synthetic-journey",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"email",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"mfa_required": true,
"credential": "none"
},
{
"client_id": "openbao-admin",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "openbao-admin",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"email",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"credential": "none"
},
{
"client_id": "rapp-qonto-client",
"principal_type": "SERVICE",
"client_type": "confidential",
"grant_types": [
"client_credentials"
],
"audience": "rapp-qonto-client",
"audience_source": "client-id-default",
"scopes": [
"qonto:read"
],
"service_subject": "rapp-qonto",
"tenant": "tenant:friendly:binky",
"roles": [
"qonto-reader"
],
"token_lifetime": "15m",
"credential": "env-ref"
},
{
"client_id": "secrets-engine-approval",
"principal_type": "SERVICE",
"client_type": "confidential",
"grant_types": [
"client_credentials"
],
"audience": "approval-engine",
"audience_source": "registration",
"scopes": [
"approval:read",
"approval:consume"
],
"service_subject": "service:secrets-engine",
"tenant": "tenant:platform",
"roles": [
"secrets-engine"
],
"token_lifetime": "15m",
"credential": "env-ref"
},
{
"client_id": "secrets-engine-openbao",
"principal_type": "SERVICE",
"client_type": "confidential",
"grant_types": [
"client_credentials"
],
"audience": "secrets-engine-openbao",
"audience_source": "client-id-default",
"scopes": [
"openbao:login"
],
"service_subject": "service:secrets-engine",
"tenant": "tenant:platform",
"roles": [
"secrets-engine"
],
"token_lifetime": "15m",
"credential": "env-ref"
},
{
"client_id": "secrets-engine-requester",
"principal_type": "SERVICE",
"client_type": "confidential",
"grant_types": [
"client_credentials"
],
"audience": "approval-engine",
"audience_source": "registration",
"scopes": [
"approval:create"
],
"service_subject": "secrets-engine",
"tenant": "tenant:platform",
"roles": [
"secrets-engine-requester"
],
"token_lifetime": "15m",
"credential": "env-ref"
},
{
"client_id": "user-engine-portal",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "user-engine-portal",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"email",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"credential": "none"
},
{
"client_id": "vergabe-demo-company",
"principal_type": "HUMAN",
"client_type": "public",
"grant_types": [
"authorization_code"
],
"audience": "vergabe-demo-company",
"audience_source": "client-id-default",
"scopes": [
"openid",
"profile",
"groups"
],
"roles": [],
"token_lifetime": "15m",
"credential": "none"
}
],
"directory_bind": {
"url": "ldap://lldap.sso.svc.cluster.local:3890",
"bind_dn": "uid=svc-keycape,ou=people,dc=netkingdom,dc=local",
"base_dn": "dc=netkingdom,dc=local",
"password_in_config": false,
"password_source": "",
"bind_is_directory_admin": false
},
"factor_service": {
"base_url": "http://privacyidea.mfa.svc.cluster.local:8080",
"realm": "coulomb",
"admin_credential": "file",
"require_for_all": true
},
"upstream_oidc": {
"base_url": "http://authelia.sso.svc.cluster.local:9091",
"client_id": "keycape",
"client_secret": "inline"
},
"admin_surfaces": [
{
"path": "/platform/authentication-policy",
"enabled": "when KEYCAPE_POLICY_PATH is set (deployment env, not config)",
"authority": "KeyCape token with azp user-engine-portal, role platform-operator, assurance aal2 with mfa within 300s"
},
{
"path": "/introspect",
"enabled": "no",
"authority": "confidential client authentication; only tokens issued to the caller"
},
{
"path": "/revoke",
"enabled": "no",
"authority": "confidential client authentication; only tokens issued to the caller"
}
],
"findings": []
}

View file

@ -74,12 +74,12 @@ identities:
owner: "key-cape owners and the consuming service owner"
rotation: {path: "Mint in custody, then deliver (credential broker); KeyCape reads it at start", coupling: [keycape, informed-decision-sitting]}
status: active
- name: rapp-qonto
- name: rapp-qonto-client
principal_type: SERVICE
purpose: "Confidential OIDC client; its token scopes are not established in the repository"
purpose: "Confidential OIDC client for rapp-qonto: scope qonto:read, role qonto-reader, tenant tenant:friendly:binky (live view 2026-11-07, KEY-WP-0045-T02)"
grants:
- {mode: USE, scope: keycape, activation: STANDING, environments: [PRODUCTION], note: "client credentials"}
- {mode: unknown, scope: "token scopes", note: "reference config: rapp-qonto-client, qonto:read; confirm live (KEY-WP-0045-T02)"}
- {mode: OBSERVE, scope: "qonto: qonto:read", activation: STANDING, environments: [PRODUCTION], note: "role qonto-reader; observed live 2026-11-07"}
interactive_login: false
second_factor: not_applicable
custody: [delivered-secret]

View file

@ -195,7 +195,7 @@ status: wait
priority: medium
assignee: claude-code
depends_on: [NK-WP-0054-T03]
blocking_reason: "Rerun 2026-11-07 on a fresh export: 0 non-conformant (keycape alias disabled, confirmed). Open: railiance-platform answers on the platform-admin max TTL and 14 undeclared roles, the founder's KeyCape live view (KEY-WP-0045-T02), then the posture-feedback feed."
blocking_reason: "Rerun 2026-11-07 on a fresh export: 0 non-conformant (keycape alias disabled, confirmed). Open: railiance-platform answers on the platform-admin max TTL and 14 undeclared roles, key-cape on approval-engine-operator and the inline upstream secret (KeyCape live view done), then the posture-feedback feed."
state_hub_task_id: "c8db4607-9306-572b-a3cb-c35ca5989ec7"
```
@ -255,6 +255,13 @@ remains, and the session survived. **Confirmed by the 14:34Z fresh export:** the
non-conformant and 14 unknown among undeclared roles. The executor's write role is absent between runs, as
CCR-2026-0058 requires, and is now checked as window-scoped.
**2026-11-07 KeyCape live view** (KEY-WP-0045-T02, founder-run;
[evidence](../docs/evidence/2026-11-07-nk-wp-0054-t04-conformance/README.md)). The five declared service clients
match their live scopes, the directory bind is `svc-keycape` (not admin), and the factor service has
`require_for_all`. The declaration now uses the live name `rapp-qonto-client` (`qonto:read`). Routed to key-cape
(message `0e9c2553`): `approval-engine-operator` is still registered with `approval:approve`, and the upstream
Authelia secret is inline in config.
## Split the directory bind from the human admin
```task