identity: Forgejo Actions as a Google WIF issuer; pin + back up the ID-token key #43
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
key-store/key.store!43
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "identity/forgejo-actions-wif-issuer"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
KSE-0182 Amendment A — phase 1, CI leg, part 1 of 2 (part 2 =
cloud-tofu.ymlswitching to the job token once this is applied).What
[actions] ID_TOKEN_SIGNING_PRIVATE_KEY_FILEto Forgejo's own default (no re-key),RS256,ID_TOKEN_EXPIRATION_TIME = 600; addforgejo-actions-id-token-key-backup.{service,timer}— daily age-encrypted copy of the CI signing key (founder + forge recipients) into the backups bucket. Nothing backed up/var/lib/forgejofile state before.infra/identity/wif.tf: import the existingkey-store-authentikpool (existence-only management:prevent_destroy,ignore_changes = all), add theforgejo-actionsOIDC provider (issuerhttps://git.key.store/api/actions; mappingsub/repository/ref/workflow_ref/event_name; conditionrepository == key-store/key.store), and grant the repo's principalSetroles/iam.workloadIdentityUseronrelease-signing@key-d0t-storeso cloud-tofu can impersonate it with a job token (parity with today's Authentik blast radius; narrow toworkflow_refin phase 3).Verified
tofu fmt/validateclean (OpenTofu 1.11.8).nixos-rebuild dry-activateon the forge builds; renderedapp.inihas the three[actions]keys; backup unit + timer in the closure.identityis dispatched from this branch — link in comments.To apply
cloud-tofu.yml→ stackidentity, modeapply(founder-gated). Expected: 1 import (pool), 2 creates (provider, SA IAM member).🤖 Generated with Claude Code
Plan results and a bootstrap prerequisite.
manage_google = false, and I had gated the WIF resources on it. Fixed ine6979a1e(WIF managed independently; the pool pre-exists and the job always has Google creds).iam.workloadIdentityPools.get— cloud-tofu.yml impersonatesrelease-signing@, which has KMS-scoped roles only.Rather than widen the release SA, the third commit gives OpenTofu its own principal (KSE-0182 A.4):
Scripts/release/provision-cloud-tofu-identity.shcreatescloud-tofu@key-d0t-storewith the admin roles the stacks manage (WIF pool admin, SA admin, KMS admin, storage admin, service-usage admin — no project IAM admin) and bindsworkloadIdentityUserfor the Authentik cloud-signing principalSet (temporary) and the Forgejo repository principalSet.cloud-tofu.ymlimpersonatesvars.GOOGLE_TOFU_SERVICE_ACCOUNT_EMAILwhen set.Founder action needed (one-time, needs Google admin):
then set the Actions variable
GOOGLE_TOFU_SERVICE_ACCOUNT_EMAIL=cloud-tofu@key-d0t-store.iam.gserviceaccount.com. After that: dispatchcloud-tofu.ymlstack=identity mode=apply → 1 import + 2 creates, and part 2 (job-token consumer) follows.4th commit: aligned with KSE-0166 + folded in the consumer.
forgejo-cloud-tofu-plan,forgejo-cloud-tofu-apply):allowed_audiences= the KSE-0166 audience, condition = repository + exactrepo:key-store/key.store:ref:refs/heads/mainsubject, constantattribute.authorityfor IAM. Both main-only for now (a branch job could otherwise mint a plan token and impersonate an admin SA); follow-up is a viewer-only plan SA.cloud-tofu.yml:enable-openid-connect: trueon the job + a gated step (Actions varKEYSTORE_CLOUD_TOFU_FORGEJO_WIF=true) that runsforgejo-ci-trust-guard.sh --mode trusted-manual --allow-manual --ref refs/heads/main --audience key-store-cloud-tofu-<plan|apply> --write-oidc-tokenand exchanges it withgoogle-wif-auth.shatforgejo-cloud-tofu-<authority>for the cloud-tofu SA. Inert until the variable is set, so this merges before the apply.provision-cloud-tofu-identity.shbindsattribute.authority/cloud-tofu-*; KSE-0182 A + Nix comment corrected toenable-openid-connect: true/ KSE-0166 audiences.Verified:
tofu fmt/validateclean; workflow YAML parses.Founder sequence (unchanged): run
provision-cloud-tofu-identity.shwith admin creds → setGOOGLE_TOFU_SERVICE_ACCOUNT_EMAIL→ merge → dispatch identity apply (1 import, 2 providers, 2 IAM members) → setKEYSTORE_CLOUD_TOFU_FORGEJO_WIF=true→ dispatch identity plan on main to prove the job-token path → remove the temporary Authentik binding on the SA.80829e76275b8b7e6944Phase 1 CI leg — done end to end (2026-08-16).
cloud-tofu@created);GOOGLE_TOFU_SERVICE_ACCOUNT_EMAILset.5b8b7e69); #50 fixed Google's 32-char provider display-name cap; #53 made the SA impersonation binding authoritative.main: identity plan 171611 to import, 4 to add→ apply 17162 (partial: display-name cap) → apply 17170Apply complete! 3 added, 1 changed.KEYSTORE_CLOUD_TOFU_FORGEJO_WIF=true→ plan 17176:ok: Forgejo CI trust guard accepted mode=trusted-manual … ref=refs/heads/main→Google identity for OpenTofu: Forgejo job token (authority cloud-tofu-plan) -> cloud-tofu@→No changes. Your infrastructure matches the configuration.workloadIdentityUserbinding oncloud-tofu@(onlyattribute.authority/cloud-tofu-{plan,apply}) — the temporary Authentik binding is gone; OpenTofu is the sole authority over its own identity.Pending: the forge switch for the Nix half (Forgejo
[actions]ID-token settings + daily key backup) — needs the founder-gateddeploy-forge-hostdispatch (restarts forgejo.service briefly). Next: KSE-0182 A.5 phase 1 host leg (Authentikkey-store-forge-host+google-wif-credentials.service+ seal/archive IAM), then phase 2 (OpenBao up; wireinfra/openbaointo cloud-tofu.yml — it isn't a supported stack there yet).