A first Terraform apply against a new Google Cloud project, in the order that works
Six steps that remove the four failures that stop a first apply: enable the services, create and version the state bucket, wire the gcs backend and migrate, authenticate without a key, pin the provider, then plan before apply. Each step says what it prevents.
markdownguidev1T9SJ-G1Q2stage: deploytrust: officialfamily: iacservice: terraforminterface: iacterraform applybackend "gcs"terraform init -migrate-stategcloud services enablegcloud storage buckets createprovider pinningterraform plan
A first Terraform apply, in order
Step 1 — enable the services first
gcloud services list
gcloud services enable SERVICE
Several at once is supported: gcloud services enable bigquery.googleapis.com pubsub.googleapis.com. You need
Service Usage Admin (roles/serviceusage.serviceUsageAdmin).
Prevents: the commonest first-apply failure, which looks like a resource problem and is a project problem
(reference/iac/errors.md §1). Put the enablements in the configuration, so project number twelve does not
need a runbook.
Step 2 — create the state bucket, and turn versioning on
Create the bucket before the backend block exists. Then:
- enable object versioning — the vendor's own tutorial does, so that "earlier versions of the state are
preserved in the bucket";
- lock it down: IAM only, and public access prevention
(reference/storage/cloud-storage-access-control.md).
Prevents: the one unrecoverable failure in a Terraform estate. A truncated state write on an unversioned bucket has nothing to restore from.
Step 3 — wire the backend, then migrate
terraform {
backend "gcs" {
bucket = "BUCKET_NAME"
}
}
terraform init -migrate-state
Prevents: losing the local state you already have. init without -migrate-state leaves it behind.
Step 4 — authenticate without a key
Pick one, in this order of preference:
- the attached identity — the runner is a Google Cloud resource (Cloud Build, a GCE instance, GKE with
Workload Identity Federation), so it already has one;
- workload identity federation — the runner is outside Google Cloud
(guides/identity/github-actions-without-keys.md);
- impersonation from your own credentials, for local work.
Prevents: a key in a repository, a CI secret store, or a developer's home directory. Keys are "a security risk if not managed correctly", and the vendor names all three alternatives above.
Step 5 — pin the provider
The hub's rule, not the vendor's — the Terraform-on-Google-Cloud page makes no version recommendation.
Pin an exact provider version in required_providers.
Prevents: a plan that differs between two runs of the same configuration, which is the hardest IaC bug to reason about because nothing in your repository changed.
Step 6 — plan, read the plan, then apply
Read every destroy and replace line before applying. On Google Cloud specifically, watch for:
- a zonal disk being replaced: it cannot move zone, so a zone change is a destroy-and-create of the data
(reference/overview/regions-zones-and-locations.md §3);
- anything in Cloud KMS: key rings cannot be deleted, deleted key names cannot be reused, and protection
level, purpose and type are immutable, so a "change" is a new key
(reference/identity/secret-manager-and-kms.md §2);
- a project being destroyed. Nothing in this hub's register justifies that in a first apply.
If Infra Manager is doing the applying, step 6 is its preview object, and steps 2 and 3 are unnecessary
because it keeps the state itself (reference/iac/terraform-on-google-cloud.md §3).
Before you write a module
Check Blueprints — Google publishes "deployable, reusable Terraform modules" — for the thing you are about to model. A landing zone, a network or a GKE cluster is almost certainly already there, and reading one is also the fastest way to learn the idioms this guide assumes.