the-custodian/docs/changes/netkingdom-target-2026-10-16/mason-browser/forgejo-1.2-source-render.json
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

385 lines
19 KiB
JSON

{
"apiVersion": "netkingdom.io/security-case-render/v0.1",
"kind": "SecurityCaseRender",
"case": "forgejo-netkingdom-oidc",
"type": "oidc-browser-relying-party@1.2",
"composition": {
"apiVersion": "netkingdom.io/security-scenario-composition/v0.1",
"kind": "SecurityScenarioComposition",
"scenario": "scenario:case:forgejo-netkingdom-oidc",
"authority": "netkingdom",
"composition_digest": "sha256:f51e45eab2f2c15c93e2f7b8ef7d8fcc1daf1059da5749429ff5678b45c5214f",
"requested_capabilities": [
"c1.lightweight-sso"
],
"capability_providers": {
"c1.lightweight-sso": "net-kingdom.keycape-client-registration"
},
"initial_trust": [
"runtime_identity_trust",
"runtime_secret_trust"
],
"planned_final_trust": [
"runtime_identity_trust",
"runtime_secret_trust",
"tenant_onboarding_trust"
],
"execution": {
"mode": "plan-only",
"permitted": false,
"reason": "Composition does not authorize or perform provider execution."
},
"execution_steps": [
{
"order": 1,
"declaration_id": "net-kingdom.keycape-client-registration",
"executor_owner": "net-kingdom",
"repo": "net-kingdom",
"capabilities": [
"c1.lightweight-sso"
],
"entry_point": {
"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 in the live KeyCape client registry without exporting secret values: contained kubectl, cluster and issuer pins, byte-preserving merge, compare-and-swap, read-back. Replaces the per-client helpers beside it. Field rules follow key-cape's canonical model (KEY-WP-0028). Modes: inspect, dry-run, apply; operations add and remove."
},
"parameters": {
"allowed_scopes": {
"value": "openid,profile,email,groups",
"source": "override",
"sensitivity": "security_sensitive",
"tuning_authority": "netkingdom_tunable"
},
"client_id": {
"value": "forgejo",
"source": "override",
"sensitivity": "operational",
"tuning_authority": "netkingdom_tunable"
},
"client_type": {
"value": "confidential",
"source": "override",
"sensitivity": "security_sensitive",
"tuning_authority": "netkingdom_tunable"
},
"display_name": {
"value": "Forgejo source forge",
"source": "override",
"sensitivity": "public",
"tuning_authority": "netkingdom_tunable"
},
"mfa_required": {
"value": "true",
"source": "override",
"sensitivity": "security_sensitive",
"tuning_authority": "netkingdom_tunable"
},
"redirect_uris": {
"value": "https://forgejo.coulomb.social/user/oauth2/netkingdom/callback",
"source": "override",
"sensitivity": "security_sensitive",
"tuning_authority": "netkingdom_tunable"
}
},
"requires_trust": [
{
"state": "runtime_secret_trust",
"readiness_checks": []
},
{
"state": "runtime_identity_trust",
"readiness_checks": []
}
],
"satisfies_trust": [
{
"state": "tenant_onboarding_trust",
"readiness_checks": [
{
"id": "client-authorize-accepts-registered-redirect",
"description": "The authorization endpoint accepts the client with each registered redirect URI.",
"evidence": "GET /authorize with client_id and each redirect_uri returns the login page, not an error."
},
{
"id": "client-authorize-refuses-other-redirect",
"description": "The authorization endpoint refuses an unregistered redirect URI for the client.",
"evidence": "GET /authorize with an unregistered redirect_uri returns an OAuth error."
}
]
}
],
"readiness_obligations": [
{
"state": "tenant_onboarding_trust",
"checks": [
{
"id": "client-authorize-accepts-registered-redirect",
"description": "The authorization endpoint accepts the client with each registered redirect URI.",
"evidence": "GET /authorize with client_id and each redirect_uri returns the login page, not an error."
},
{
"id": "client-authorize-refuses-other-redirect",
"description": "The authorization endpoint refuses an unregistered redirect URI for the client.",
"evidence": "GET /authorize with an unregistered redirect_uri returns an OAuth error."
}
]
}
]
}
],
"responsibility_map": [
{
"declaration_id": "net-kingdom.keycape-client-registration",
"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."
},
{
"declaration_id": "net-kingdom.keycape-client-registration",
"resource_kind": "roles_scopes_policies",
"owner": "key-cape",
"resources": [
"iam-profile:client-scope-allowlists"
],
"repo_owns": "Enforce exact redirect URIs, allowed scopes and the MFA pin at authorization time.",
"netkingdom_orchestrates": "Choose scopes and MFA posture per SecurityCaseType."
}
]
},
"materialization": [
{
"id": "client-secret-path",
"kind": "kv_path",
"template": "platform/workloads/keycape/forgejo",
"body": "field CLIENT_SECRET; minted by the credential broker, never written by hand"
},
{
"id": "keycape-reader-policy",
"kind": "openbao_policy",
"template": "workload-kv-read-keycape-forgejo-eso",
"body": "path \"platform/data/workloads/keycape/forgejo\" {\n capabilities = [\"read\"]\n}\n",
"description": "KeyCape reads its client secret only through ESO. No metadata, list, parent or sibling access."
},
{
"id": "consumer-reader-policy",
"kind": "openbao_policy",
"template": "workload-kv-read-keycape-forgejo-forgejo",
"body": "path \"platform/data/workloads/keycape/forgejo\" {\n capabilities = [\"read\"]\n}\n",
"description": "The consuming service reads the same secret. No metadata, list, parent or sibling access."
},
{
"id": "eso-role",
"kind": "openbao_role",
"template": "external-secrets-keycape-forgejo",
"body": "auth: kubernetes\nbound_service_account_names: [external-secrets]\nbound_service_account_namespaces: [external-secrets]\ntoken_policies: [workload-kv-read-keycape-forgejo-eso]\ntoken_no_default_policy: true\ntoken_ttl: 15m\ntoken_max_ttl: 15m\n",
"description": "The Kubernetes-auth role deliver-secret uses; bound to the ESO service account only."
},
{
"id": "consumer-eso-role",
"kind": "openbao_role",
"template": "external-secrets-keycape-forgejo-forgejo",
"body": "auth: kubernetes\nbound_service_account_names: [forgejo-keycape-forgejo-eso]\nbound_service_account_namespaces: [forgejo]\naudience: openbao\ntoken_policies: [workload-kv-read-keycape-forgejo-forgejo]\ntoken_no_default_policy: true\ntoken_ttl: 15m\ntoken_max_ttl: 15m\n",
"description": "Consumer ESO requests a token for this separate reference identity. Common ESO controller remains trusted and can request tokens; no cryptographic controller isolation is claimed."
},
{
"id": "catalog-entry",
"kind": "catalog_entry",
"template": "forgejo-keycape-client",
"body": "id: forgejo-keycape-client\nowner_repo: key-cape\nwarden_executes: false\nrisk: high\nstatus: active once verification passes\nworkload_ref: applicable, name forgejo, declaration_ref of the consumer's published declaration or the explicit unknown form, never inferred\npath_template: platform/workloads/keycape/forgejo\nfield: CLIENT_SECRET\ndelegation: native, intended_owner key-cape\nrotation: mint-secret then verification; automatable false until a run has been proven\n",
"description": "One entry per case (ops-mason item 5, ops-warden R4'). It carries the consumer's workload reference, which ADR-0009 needs for zone selection."
}
],
"follow_through": [
{
"id": "ensure-groups",
"owner": "net-kingdom",
"entry_point": "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)",
"auth": "operator cluster access in the attended register-client session; the in-pod call uses the provisioner's own directory binding, and no provisioner or user-engine token is read or sent",
"lane": "key-cape-oidc-login",
"warden_executes": false,
"attended": true,
"value_handling": "none",
"attended_justification": "The provisioner's only HTTP credential is user-engine's runtime token, and its NetworkPolicy admits only user-engine pods. A proxy lane would act as user-engine (ops-warden review R8; canon section 3; ops-warden ADR-0002). Running it in the session register-client already needs adds no attended session. It can become unattended once the provisioner has an operator credential of its own and an admitted path."
},
{
"id": "mint-secret",
"owner": "railiance-platform",
"entry_point": "railiance-platform credential broker: generate a client secret inside custody at bao:platform/workloads/keycape/forgejo",
"auth": "the caller's broker grant for the case's KV path, through its lane; the value is generated in custody and never returned",
"lane": "keycape-client-secret-generate",
"warden_executes": true,
"attended": false,
"value_handling": "generated_in_custody"
},
{
"id": "deliver-secret",
"owner": "railiance-platform",
"entry_point": "ExternalSecret sso/keycape-forgejo-client (key client-secret) from bao:platform/workloads/keycape/forgejo",
"auth": "railiance-platform ESO delivery through role external-secrets-keycape-forgejo; no value leaves custody",
"warden_executes": false,
"attended": false,
"value_handling": "none",
"ready_check": "the delivery for sso/keycape-forgejo-client reports Ready=True (status only, no value read)"
},
{
"id": "bind-env",
"owner": "net-kingdom",
"entry_point": "patch Deployment sso/keycape: env KEYCAPE_FORGEJO_CLIENT_SECRET from sso/keycape-forgejo-client",
"auth": "operator kube credentials for namespace sso",
"lane": "key-cape-oidc-login",
"warden_executes": false,
"attended": true,
"value_handling": "none",
"attended_justification": "A change to the live identity provider's Deployment. It runs in the same attended operator session as register-client, before it, because KeyCape resolves a confidential client's secret at start and fails closed if the binding is missing."
},
{
"id": "register-client",
"owner": "net-kingdom",
"entry_point": "sso-mfa/k8s/keycape/keycape-client.py apply --client-file <client-from-case> --case-acceptance <record> --check-config <keycape binary> (net-kingdom.keycape-client-registration)",
"auth": "operator write access to the live KeyCape client registry in namespace sso",
"lane": "key-cape-oidc-login",
"warden_executes": false,
"attended": true,
"value_handling": "none",
"attended_justification": "The live KeyCape client registry is a Kubernetes Secret, and agents do not read or write Secrets. Until KeyCape loads clients from a non-secret registry with secrets referenced from custody, one attended operator session applies the rendered registration. ops-warden groups all attended steps of a run into that one session. KeyCape loads clients at startup and keeps login, authorization and handoff state in memory, so the restart drops in-flight logins and sessions for every client; runs go in a quiet window (key-cape type review R4). The rendered registry must pass KeyCape's own startup checks (keycape check-config, key-cape c528daa, which keycape-client.py runs before it patches) before the restart: a refused entry stops the single replica and every client loses sign-in (R1)."
},
{
"id": "deliver-consumer-secret",
"owner": "railiance-apps",
"entry_point": "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.",
"auth": "Consumer owner contained Kubernetes deployment authority; ESO authenticates to OpenBao role external-secrets-keycape-forgejo-forgejo with a TokenRequest for the dedicated namespaced serviceAccountRef; controller remains trusted",
"warden_executes": false,
"attended": false,
"value_handling": "none",
"ready_check": "Namespace SecretStore and ExternalSecret both report Ready=True; dedicated SA has no legacy token refs; status and fixed metadata only, never Secret values."
},
{
"id": "hand-over",
"owner": "railiance-apps",
"entry_point": "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",
"auth": "the consumer owner's own deployment path",
"warden_executes": false,
"attended": false,
"value_handling": "none"
}
],
"verification": [
{
"id": "authorize-accepts-redirects",
"check": "GET https://kc.coulomb.social/authorize with client forgejo and each of https://forgejo.coulomb.social/user/oauth2/netkingdom/callback returns the login page",
"expect": "present",
"reads_secret_value": false
},
{
"id": "authorize-refuses-other-redirect",
"check": "GET https://kc.coulomb.social/authorize with client forgejo and an unregistered redirect returns an OAuth error",
"expect": "deny",
"reads_secret_value": false
},
{
"id": "custody-denied-to-default",
"check": "a default-only OpenBao identity has no read capability on bao:platform/workloads/keycape/forgejo",
"expect": "deny",
"reads_secret_value": false
},
{
"id": "custody-allowed-to-consumer",
"check": "policy workload-kv-read-keycape-forgejo-forgejo grants read on bao:platform/workloads/keycape/forgejo (capabilities check only)",
"expect": "allow",
"reads_secret_value": false
},
{
"id": "groups-present",
"check": "LLDAP groups forge-admins,forge-coulomb-owners,forge-coulomb-readers exist, with exactly the memberships of the accepted case added",
"expect": "present",
"reads_secret_value": false
},
{
"id": "consumer-enforces-groups",
"check": "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)",
"expect": "present",
"reads_secret_value": false
},
{
"id": "secret-delivered",
"check": "the delivery for sso/keycape-forgejo-client reports Ready=True (status only)",
"expect": "present",
"reads_secret_value": false
},
{
"id": "mfa-pinned",
"check": "keycape-client.py inspect for forgejo shows the MFA pin on the registered client (non-secret client view)",
"expect": "present",
"reads_secret_value": false
},
{
"id": "consumer-secret-delivered",
"check": "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",
"expect": "present",
"reads_secret_value": false
}
],
"rollback": [
{
"reverses": "hand-over",
"action": "remove the OIDC source for forgejo from forgejo (owner railiance-apps)"
},
{
"reverses": "deliver-consumer-secret",
"action": "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."
},
{
"reverses": "register-client",
"action": "keycape-client.py apply --operation remove for forgejo"
},
{
"reverses": "bind-env",
"action": "remove env KEYCAPE_FORGEJO_CLIENT_SECRET from Deployment sso/keycape, after register-client is reversed"
},
{
"reverses": "deliver-secret",
"action": "delete ExternalSecret sso/keycape-forgejo-client and its target"
},
{
"reverses": "mint-secret",
"action": "covered by client-secret-path: one metadata delete, after deliver-secret is reversed"
},
{
"reverses": "ensure-groups",
"action": "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"
},
{
"reverses": "client-secret-path",
"action": "delete metadata and all versions at platform/workloads/keycape/forgejo, after the ExternalSecret is gone (this also reverses mint-secret)"
},
{
"reverses": "eso-role",
"action": "delete Kubernetes-auth role external-secrets-keycape-forgejo"
},
{
"reverses": "keycape-reader-policy",
"action": "delete policy workload-kv-read-keycape-forgejo-eso, after eso-role"
},
{
"reverses": "consumer-eso-role",
"action": "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."
},
{
"reverses": "consumer-reader-policy",
"action": "delete policy workload-kv-read-keycape-forgejo-forgejo"
},
{
"reverses": "catalog-entry",
"action": "remove catalog entry forgejo-keycape-client"
}
],
"execution": {
"permitted": false
},
"digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35"
}