the-custodian/docs/changes/netkingdom-target-2026-10-16/mason-browser/forgejo-1.2-draft-plan.md
codex 6cf0012a6e
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 3s
Reject generated-only commits / generated-commit-guard (push) Successful in 12s
docs: preserve reviewed NetKingdom session artifacts
2026-11-01 23:09:51 +01:00

8.4 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.2 sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35 draft null true null null

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

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

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: none (metadata only).

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

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
consumer-eso-role openbao_role external-secrets-keycape-forgejo-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

consumer-eso-role

auth: kubernetes
bound_service_account_names: [forgejo-keycape-forgejo-eso]
bound_service_account_namespaces: [forgejo]
audience: openbao
token_policies: [workload-kv-read-keycape-forgejo-forgejo]
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 --check-config (net-kingdom.keycape-client-registration)
  • deliver-consumer-secret — railiance-apps: Owner applies dedicated ServiceAccount forgejo/forgejo-keycape-forgejo-eso (automount=false, no legacy tokens), namespace SecretStore openbao-keycape-forgejo-consumer with serviceAccountRef and audiences [openbao], and ExternalSecret forgejo-netkingdom-oidc-client with Owner target, Retain remote deletion and only CLIENT_SECRET from workloads/keycape/forgejo. Admission validates actual installed ESO TokenRequest support and common controller RBAC before any owner-approved apply.
  • 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)
  • consumer-secret-delivered (present): forgejo SecretStore openbao-keycape-forgejo-consumer and ExternalSecret forgejo-netkingdom-oidc-client Ready=True, exact dedicated SA/audience role binding, fixed CLIENT_SECRET mapping; no Secret value read

Rollback, in order:

  • remove the OIDC source for forgejo from forgejo (owner railiance-apps)
  • After reverting consumer secret reference, delete only authenticated created ExternalSecret/owned target by UID and ownerReference, then SecretStore and dedicated SA; preserve preexisting-matched resources and never delete a shared target. Retain audit and ownership receipts; removing SecretStore/SA alone is not immediate OpenBao token revocation.
  • 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 only this case-created role external-secrets-keycape-forgejo-forgejo, before deleting consumer-reader-policy; revoke case-issued OpenBao tokens or prove expiration before declaring deactivation.
  • delete policy workload-kv-read-keycape-forgejo-forgejo
  • remove catalog entry forgejo-keycape-client

5. Case acceptance (replaces the executive summary)

Not accepted yet. The case must carry its acceptance record before a build.