net-kingdom/capabilities/playbooks/net-kingdom.keycape-service-client-registration.yaml
tegwick 5d5f15df55
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
NK-WP-0056-T14 done: SecurityCaseType oidc-service-client 0.1 (proposed)
Confidential client_credentials service clients: one audience, closed
resource scopes, fixed service subject and tenant, at most 15m; secret minted
in custody, read only by KeyCape (ESO) and the consumer's own bound
Kubernetes-auth role (no Secret copy). First case nk-bind-executor-approval
(approval-engine create/read/consume as service:nk-bind-executor). Capability
net-kingdom.keycape-service-client-registration; keycape-client.py renders
service clients in key-cape's shape (adoption of secrets-engine-approval
reproduces key-cape's record). Acknowledgement memo r1 validated against
informed-decision intake and State Hub dispatcher; hub decision f8044f81.
Test fixture's synthetic signing key is now computed, not a literal (secret
scan generic-api-key).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5502@bnt-lap001
Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196
2026-10-31 21:30:21 +01:00

135 lines
5.4 KiB
YAML

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 <client.yaml> --case-acceptance <record> --expected-uid <uid> --expected-resource-version <rv>
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