# Burrow Identity KMS and WIF This OpenTofu stack owns Google Cloud KMS and Workload Identity Federation resources for Burrow identity and release automation. It may manage: - the `burrow-identity` Google KMS key ring - non-exportable KMS signing keys for Authentik, the SAML CA, and release signing - dedicated non-exportable KMS signing keys for APT, RPM, pacman, Flatpak, and AUR source release surfaces - a non-exportable KMS signing key for the Apple Developer ID Application CSR path (`apple-developer-id-application`) - a non-exportable KMS signing key for the Apple iOS Distribution CSR path (`apple-ios-distribution`) - a non-exportable software KMS signing key for Sparkle Ed25519 appcast signatures (`sparkle-ed25519`) - an Authentik-backed WIF pool/provider for Forgejo runners - the runner service account and its narrow IAM binding for the Authentik WIF audience/client value `google-wif.burrow.net`; human/group grants are opt-in It must not manage: - Authentik private signing key material - OpenBao bootstrap tokens - store credentials or service-account JSON keys Forgejo CI should authenticate with `Scripts/ci/google-wif-auth.sh`. That helper uses Authentik to obtain an OIDC token and lets Google WIF impersonate `burrow-forgejo-runner@project-88c23ce9-918a-470a-b33.iam.gserviceaccount.com` in project `project-88c23ce9-918a-470a-b33`. ## Apple Developer ID CSR `Scripts/apple/google-kms-csr.py` builds a standard PKCS#10 CSR using the public key from `projects/project-88c23ce9-918a-470a-b33/locations/global/keyRings/burrow-identity/cryptoKeys/apple-developer-id-application` and asks Google KMS to sign the CSR payload. The private key remains non-exportable in KMS. Forgejo can generate the Apple-uploadable CSR with: ```sh Scripts/forgejo-dispatch.sh apple-developer-id-kms-csr.yml --ref main ``` Apple currently documents Developer ID certificate creation through the Developer website or Xcode. After downloading the returned `.cer`, keep it with release artifacts; do not convert this key path into an exportable `.p12`. The active certificate created from this path is Apple certificate `9JKN6HXBHC`, stored at `Apple/Certificates/developer-id-application-9JKN6HXBHC.cer`. Its public key matches KMS key version `apple-developer-id-application/cryptoKeyVersions/1`. ## Apple iOS Distribution CSR The iOS App Store distribution certificate uses the same CSR builder with the `apple-ios-distribution` KMS key: ```sh Scripts/apple/google-kms-csr.py \ --kms-key apple-ios-distribution \ --common-name "Burrow iOS Distribution" \ --output ios-distribution.certSigningRequest ``` The App Store Connect API can create the certificate from that CSR: ```sh Scripts/apple/create-asc-certificate.mjs \ --certificate-type IOS_DISTRIBUTION \ --csr-file ios-distribution.certSigningRequest \ --out-dir Apple/Certificates ``` The active certificate created from this path is Apple certificate `3G42677598`, stored at `Apple/Certificates/ios-distribution-3G42677598.cer`. Its public key matches KMS key version `apple-ios-distribution/cryptoKeyVersions/1`. ## Sparkle Appcast Signing Sparkle appcasts keep `sparkle-ed25519`, a Google KMS key with algorithm `EC_SIGN_ED25519` and software protection level, for small signing probes and future signing-service work. Google KMS rejects Ed25519 at HSM protection level and also rejects full-size macOS release archives as direct Ed25519 messages. The tester pipeline therefore signs normal Sparkle archives with Sparkle's `sign_update` and the decrypted `SPARKLE_EDDSA_KEY_PATH` release secret so the appcast contains the standard full-archive EdDSA signature Sparkle verifies. The public EdDSA key embedded in macOS release builds is: ```text uugZuJeqvvKd91NZ6F1Fv2cQenUbIG/ZW3L9MuaEz30= ``` The appcast signer is: ```sh Scripts/sparkle/sign-appcast-kms.py \ --appcast dist/builds//sparkle//appcast.xml \ --artifact-dir dist/builds//sparkle/ ``` ## Run ```sh Scripts/identity-tofu.sh init -backend-config=backend.hcl Scripts/identity-tofu.sh plan -var-file=terraform.tfvars ``` For local syntax work without remote state: ```sh Scripts/identity-tofu.sh init -backend=false Scripts/identity-tofu.sh validate ``` Start with `manage_google = false`. Import existing resources before enabling management, then turn on one resource group at a time. ## Bootstrap Imports The first live Apple Developer ID pass may need these resources imported before an `identity` apply can own them: ```sh Scripts/identity-tofu.sh import 'google_kms_key_ring.identity[0]' \ projects/project-88c23ce9-918a-470a-b33/locations/global/keyRings/burrow-identity Scripts/identity-tofu.sh import 'google_kms_crypto_key.signing["apple_developer_id_application"]' \ projects/project-88c23ce9-918a-470a-b33/locations/global/keyRings/burrow-identity/cryptoKeys/apple-developer-id-application Scripts/identity-tofu.sh import 'google_kms_crypto_key.signing["apple_ios_distribution"]' \ projects/project-88c23ce9-918a-470a-b33/locations/global/keyRings/burrow-identity/cryptoKeys/apple-ios-distribution Scripts/identity-tofu.sh import 'google_kms_crypto_key.signing["sparkle_ed25519"]' \ projects/project-88c23ce9-918a-470a-b33/locations/global/keyRings/burrow-identity/cryptoKeys/sparkle-ed25519 Scripts/identity-tofu.sh import 'google_service_account.runner[0]' \ projects/project-88c23ce9-918a-470a-b33/serviceAccounts/burrow-forgejo-runner@project-88c23ce9-918a-470a-b33.iam.gserviceaccount.com ``` Run imports with the same `manage_google`, key-ring, and service-account variables that will be used for apply. Key-level IAM bindings should be imported after the signing keys and service account exist.