# 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.
