Wire Forge-native release infrastructure
Some checks failed
Cache: Publish Nix / Publish Nix Cache (push) Waiting to run
Build Rust / Cargo Test (push) Successful in 4m14s
Build Site / Next.js Build (push) Failing after 6s
Infra: OpenTofu / OpenTofu (grafana) (push) Successful in 5s
Lint Governance / BEP Metadata (push) Successful in 0s
Build: Android / Android Rust Core Stub (push) Failing after 23s

This commit is contained in:
Conrad Kramer 2026-06-07 05:51:12 -07:00
parent 97c569fb35
commit 002bd382e9
199 changed files with 14268 additions and 185 deletions

145
infra/identity/README.md Normal file
View file

@ -0,0 +1,145 @@
# 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 bindings for the
`burrow-automation` group and the Authentik WIF client ID
`google-wif.burrow.net`
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 use `sparkle-ed25519`, a non-exportable Google KMS key with
algorithm `EC_SIGN_ED25519` and software protection level. Google KMS rejects
Ed25519 at HSM protection level, so this key is intentionally separate from the
HSM RSA keys used for Apple certificate CSRs and repository signing.
The public EdDSA key embedded in macOS release builds is:
```text
Myv9ZNZT6YGKMtMezh52ra4WqaeEKc4VlvVU0evhJeI=
```
The appcast signer is:
```sh
Scripts/sparkle/sign-appcast-kms.py \
--appcast dist/builds/<build>/sparkle/<channel>/appcast.xml \
--artifact-dir dist/builds/<build>/sparkle/<channel>
```
## 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.