ops-mason/plans/case-forgejo-netkingdom-oidc.md
tegwick 2ef0101412 WP-0009-T05 invariant (ii) verified; survey policy covers keycape-services roles; Forgejo plan re-rendered
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 327203@bnt-lap001
Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
2026-10-10 14:13:02 +02:00

7.2 KiB

id demand_source consumer_repo credential_type derived_from_type render_digest status case_acceptance reference_case approved_by approved_at
case-forgejo-netkingdom-oidc SecurityCase forgejo-netkingdom-oidc (owner railiance-apps) railiance-apps security-case oidc-browser-relying-party@1.1 sha256:af1f4f81ef313f5e086e6e3de17197d9112dd40f00b4c20b52b5ca73c7a6d18a reviewed
record at by
key-cape docs/forgejo-oidc-client-request.yaml (status accepted-2026-10-08, KEY-WP-0038-T01); type acknowledged via informed-decision memo nk-wp-0048-t05-oidc-browser-relying-party-r4, hub decision e418263e 2026-10-08
owner
founder
true null null

Construction plan (derived-from-type): forgejo-netkingdom-oidc

Rendered from oidc-browser-relying-party@1.1 (Browser OIDC relying party for an internal service). Do not edit by hand: re-run ops-mason plan --case instead. Render digest sha256:af1f4f81ef313f5e086e6e3de17197d9112dd40f00b4c20b52b5ca73c7a6d18a.

Reference case: the type is acknowledged, not yet implemented. This case is the one whose live materialization takes the type to implemented.

1. Demand

Let an internal web service sign its human users in through NetKingdom (KeyCape): an exact-redirect OIDC client, optional MFA pin, the LLDAP groups the service maps to its own roles, and, for confidential clients, a client secret minted straight into OpenBao custody. Replaces the per-client rollout scripts in sso-mfa/k8s/keycape. First case: Forgejo (KEY-WP-0038).

2. Existing-structure survey

Survey source: live (metadata only).

No collision with existing policies, roles, KV paths or catalog entries.

Already present from this case's own build bundle (not collisions):

  • openbao_policy workload-kv-read-keycape-forgejo-eso

3. Objects (from the type's materialization)

Item Kind Name
client-secret-path kv_path platform/workloads/keycape/forgejo
keycape-reader-policy openbao_policy workload-kv-read-keycape-forgejo-eso
consumer-reader-policy openbao_policy workload-kv-read-keycape-forgejo-forgejo
eso-role openbao_role external-secrets-keycape-forgejo
catalog-entry catalog_entry forgejo-keycape-client

client-secret-path

field CLIENT_SECRET; minted by the credential broker, never written by hand

keycape-reader-policy

path "platform/data/workloads/keycape/forgejo" {
  capabilities = ["read"]
}

consumer-reader-policy

path "platform/data/workloads/keycape/forgejo" {
  capabilities = ["read"]
}

eso-role

auth: kubernetes
bound_service_account_names: [external-secrets]
bound_service_account_namespaces: [external-secrets]
token_policies: [workload-kv-read-keycape-forgejo-eso]
token_no_default_policy: true
token_ttl: 15m
token_max_ttl: 15m

catalog-entry

id: forgejo-keycape-client
owner_repo: key-cape
warden_executes: false
risk: high
status: active once verification passes
workload_ref: applicable, name forgejo, declaration_ref of the consumer's published declaration or the explicit unknown form, never inferred
path_template: platform/workloads/keycape/forgejo
field: CLIENT_SECRET
delegation: native, intended_owner key-cape
rotation: mint-secret then verification; automatable false until a run has been proven

4. Review notes

Shape reviewed once, when the type was acknowledged; this review checks only this case's names against existing structure (section 2).

Follow-through (ops-warden):

  • ensure-groups — net-kingdom (attended): identity-provisioner ensure_service_groups, run inside the provisioner pod through the session's contained cluster access (groups forge-admins,forge-coulomb-owners,forge-coulomb-readers; members exactly forge-admins=tegwick;forge-coulomb-owners=tegwick as recorded in the accepted case, nothing else)
  • mint-secret — railiance-platform: railiance-platform credential broker: generate a client secret inside custody at bao:platform/workloads/keycape/forgejo
  • deliver-secret — railiance-platform: ExternalSecret sso/keycape-forgejo-client (key client-secret) from bao:platform/workloads/keycape/forgejo
  • bind-env — net-kingdom (attended): patch Deployment sso/keycape: env KEYCAPE_FORGEJO_CLIENT_SECRET from sso/keycape-forgejo-client
  • register-client — net-kingdom (attended): sso-mfa/k8s/keycape/keycape-client.py apply --client-file --case-acceptance (net-kingdom.keycape-client-registration)
  • hand-over — railiance-apps: configure forgejo with issuer https://kc.coulomb.social, client forgejo and custody bao:platform/workloads/keycape/forgejo, and make it require one of forge-admins,forge-coulomb-owners,forge-coulomb-readers in the groups claim before sign-in completes

Verification:

  • authorize-accepts-redirects (present): GET https://kc.coulomb.social/authorize with client forgejo and each of https://forgejo.coulomb.social/user/oauth2/netkingdom/callback returns the login page
  • authorize-refuses-other-redirect (deny): GET https://kc.coulomb.social/authorize with client forgejo and an unregistered redirect returns an OAuth error
  • custody-denied-to-default (deny): a default-only OpenBao identity has no read capability on bao:platform/workloads/keycape/forgejo
  • custody-allowed-to-consumer (allow): policy workload-kv-read-keycape-forgejo-forgejo grants read on bao:platform/workloads/keycape/forgejo (capabilities check only)
  • groups-present (present): LLDAP groups forge-admins,forge-coulomb-owners,forge-coulomb-readers exist, with exactly the memberships of the accepted case added
  • consumer-enforces-groups (present): forgejo's OIDC source for forgejo (owner railiance-apps) requires one of forge-admins,forge-coulomb-owners,forge-coulomb-readers in the groups claim (configuration read, no secret value)
  • secret-delivered (present): the delivery for sso/keycape-forgejo-client reports Ready=True (status only)
  • mfa-pinned (present): keycape-client.py inspect for forgejo shows the MFA pin on the registered client (non-secret client view)

Rollback, in order:

  • remove the OIDC source for forgejo from forgejo (owner railiance-apps)
  • keycape-client.py apply --operation remove for forgejo
  • remove env KEYCAPE_FORGEJO_CLIENT_SECRET from Deployment sso/keycape, after register-client is reversed
  • delete ExternalSecret sso/keycape-forgejo-client and its target
  • covered by client-secret-path: one metadata delete, after deliver-secret is reversed
  • identity-provisioner revoke_service_groups inside the provisioner pod (attended, as ensure-groups) with the case's memberships; delete_if_empty only if no other case uses forge-admins,forge-coulomb-owners,forge-coulomb-readers
  • delete metadata and all versions at platform/workloads/keycape/forgejo, after the ExternalSecret is gone (this also reverses mint-secret)
  • delete Kubernetes-auth role external-secrets-keycape-forgejo
  • delete policy workload-kv-read-keycape-forgejo-eso, after eso-role
  • delete policy workload-kv-read-keycape-forgejo-forgejo
  • remove catalog entry forgejo-keycape-client

5. Case acceptance (replaces the executive summary)

Accepted by owner, founder at 2026-10-08; record key-cape docs/forgejo-oidc-client-request.yaml (status accepted-2026-10-08, KEY-WP-0038-T01); type acknowledged via informed-decision memo nk-wp-0048-t05-oidc-browser-relying-party-r4, hub decision e418263e.