--- id: case-forgejo-netkingdom-oidc demand_source: SecurityCase forgejo-netkingdom-oidc (owner railiance-apps) consumer_repo: railiance-apps credential_type: security-case derived_from_type: oidc-browser-relying-party@1.1 render_digest: sha256:af1f4f81ef313f5e086e6e3de17197d9112dd40f00b4c20b52b5ca73c7a6d18a status: reviewed case_acceptance: 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 at: '2026-10-08' by: - owner - founder reference_case: true approved_by: null approved_at: 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`.