12. Terraform for GCP Resource Management
Status
Accepted — 2026-04-19
Context
All GCP/Firebase infrastructure for jjk.engineer has been provisioned and configured manually through the Firebase Console and GCP Console (“ClickOps”). This includes enabled APIs, service accounts, IAM bindings, Secret Manager secrets, the Firestore database instance, and storage buckets. The Firebase CLI handles application-level deployment (hosting, functions, rules, indexes, Remote Config) and does so well, but the underlying GCP resource layer — the things that must exist before firebase deploy works — has no version control, no drift detection, and no reproducibility.
This has caused friction: deploying functions to a fresh environment requires manually enabling APIs in the correct order, creating service accounts, granting roles, and provisioning secrets. A missing API produces opaque errors that require multiple deploy-retry cycles to resolve.
ADR 0005 establishes Firebase as the sole infrastructure vendor. This decision does not change that — Terraform manages the GCP substrate beneath Firebase, not an alternative to it.
Decision
Use Terraform to manage GCP-level resources that underpin the Firebase project. The Firebase CLI remains the deployment tool for application artifacts.
Terraform owns (the substrate):
- Enabled GCP APIs
- Service accounts and IAM bindings
- Secret Manager secret metadata (not values)
- Firestore database instance configuration
- Storage bucket configuration
- Future: billing budgets, monitoring alerts
Firebase CLI owns (the application):
- Hosting deploys (static assets, preview channels)
- Cloud Functions code and configuration
- Firestore security rules and composite indexes
- Storage security rules
- Remote Config templates
- App Check provider configuration
The boundary is: if it must exist before firebase deploy can succeed, Terraform manages it. If it is the deploy itself, Firebase CLI manages it.
Configuration lives in infra/ at the repository root. State starts local and may move to a GCS backend when warranted.
Consequences
- The GCP resource layer is version-controlled and reviewable. Drift between intended and actual state is detectable via
terraform plan. - New environments (staging, disaster recovery) can be stood up from code rather than reconstructed from memory.
- Two deployment tools now coexist. The team must understand which tool owns which resources to avoid conflicts. This boundary is documented above and should be referenced if ambiguity arises.
- Terraform state contains resource metadata (project IDs, service account emails, secret names) but not secret values. State files are gitignored but should be treated as sensitive.
- Firebase-specific resources with limited or no Terraform support (App Check, Remote Config, Hosting sites, Cloud Functions) stay in the Firebase CLI workflow. Attempting to manage these in Terraform would create friction without value.
- This is a learning investment. The project does not strictly require IaC at its current scale, but the practice builds enterprise-grade operational skill in a low-risk environment.
See also: ADR 0005 — Firebase as Sole Infrastructure Vendor.