apiVersion: netkingdom.io/playbook-capability/v0.1 kind: PlaybookCapabilityDeclaration metadata: id: net-kingdom.keycape-service-client-registration name: KeyCape confidential service client registration (live registry) owner: net-kingdom repo: net-kingdom domain: infotech contract_version: "0.1" source_links: - label: Entry point path: sso-mfa/k8s/keycape/keycape-client.py - label: Tests path: sso-mfa/k8s/keycape/test_keycape_client.py - label: SecurityCaseType path: security-case-types/oidc-service-client/type.yaml spec: playbook: path: sso-mfa/k8s/keycape/keycape-client.py type: cli-sequence invocation: keycape-client.py apply --client-file --case-acceptance --expected-uid --expected-resource-version description: >- Add or remove exactly one client_credentials service client in the live KeyCape client registry, with the same safeguards as browser clients: contained kubectl, cluster and issuer pins, byte-preserving merge, compare-and-swap, KeyCape check-config, read-back, and no secret values. Field rules are key-cape's (src/internal/config/validate.go): confidential, env secretRef, serviceSubject and tenant required, no redirect URIs, token lifetime 1m-1h. Replaces per-client scripts such as approval-clients-rollout.py. capabilities: - id: c1.lightweight-sso tier: C1 resource_kinds: - identities - roles_scopes_policies description: Register one confidential service client with the running lightweight issuer. parameters: - name: client_id type: string required: true constraints: pattern: ^[a-z0-9][a-z0-9-]{1,62}$ sensitivity: operational tuning_authority: netkingdom_tunable description: OAuth2 client_id, unique in the registry. - name: display_name type: string required: true constraints: pattern: ^[^\n\r]{1,80}$ sensitivity: public tuning_authority: netkingdom_tunable description: Human-readable client name. - name: audience type: string required: true constraints: pattern: ^[a-z0-9][a-z0-9-]{1,62}$ sensitivity: security_sensitive tuning_authority: netkingdom_tunable description: The single resource server the tokens are for (aud). - name: allowed_scopes type: string required: true constraints: pattern: ^[a-z][a-z0-9-]*:[a-z][a-z0-9-]*(,[a-z][a-z0-9-]*:[a-z][a-z0-9-]*)*$ sensitivity: security_sensitive tuning_authority: netkingdom_tunable description: Comma-separated resource scopes of the audience; no OIDC identity scopes. - name: service_subject type: string required: true constraints: pattern: ^service:[a-z0-9][a-z0-9-]{1,62}$ sensitivity: security_sensitive tuning_authority: netkingdom_tunable description: The sub KeyCape puts into the client's tokens. - name: tenant type: string required: true constraints: pattern: ^tenant:[a-z0-9][a-z0-9-]{1,62}$ sensitivity: security_sensitive tuning_authority: netkingdom_tunable description: The registration-bound tenant claim. - name: roles type: string required: false constraints: pattern: ^[a-z][a-z0-9-]{1,62}(,[a-z][a-z0-9-]{1,62})*$ sensitivity: operational tuning_authority: netkingdom_tunable description: Comma-separated roles carried in the token. - name: token_lifetime type: string required: true constraints: pattern: ^(5|10|15)m$ sensitivity: security_sensitive tuning_authority: netkingdom_tunable description: Access-token lifetime; at most 15m (stricter than KeyCape's 1h ceiling). responsibilities: - resource_kind: identities owner: net-kingdom resources: - oidc:static-clients repo_owns: Live registry change for exactly this client, its idempotency and removal; field rules are key-cape's canonical model. netkingdom_orchestrates: Supply the case's validated, non-secret client fields. - resource_kind: roles_scopes_policies owner: key-cape resources: - iam-profile:client-scope-allowlists repo_owns: Issue client_credentials tokens only for the registered scopes, audience, subject and tenant; refuse excess scopes. netkingdom_orchestrates: Choose audience, scopes, subject and lifetime per SecurityCaseType. trust: requires: - state: runtime_secret_trust readiness_checks: [] - state: runtime_identity_trust readiness_checks: [] satisfies: - state: tenant_onboarding_trust readiness_checks: - id: service-token-claims description: A client_credentials exchange for each allowed scope returns a token with the registered sub, aud, tenant and lifetime. evidence: The consuming service's own exchange, reported as claims only (no secret or token value). - id: service-token-refuses-excess-scope description: A client_credentials exchange for a scope outside allowed_scopes is refused. evidence: KeyCape returns invalid_scope. catalog: publish: capabilities/playbooks/net-kingdom.keycape-service-client-registration.yaml maturity: implemented consumers: - netkingdom-security-scenario-composer - netkingdom-security-case-types