Infrastructure as Code
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. See the section bibliography for the reference material consulted while preparing these pages. |
Examples on this page target the gcloud CLI 586, Terraform 1.x with the hashicorp/google provider v8 (8.0.0 was
released on 2026-08-26 and v7.x still receives patches), and Infrastructure Manager, all checked on 2026-10-01.
Re-verify with gcloud --version and terraform version before relying on exact behaviour. The Bookshelf scenario
used here (a static front end, catalog-api, orders-api and the notifier worker) is described in
the section introduction; my-project-id and us-central1 are placeholders.
Declarative vs. imperative management
Google Cloud resources can be managed imperatively, by running commands such as gcloud artifacts repositories create,
or declaratively, by describing the desired end state and letting a tool work out what to create, change or delete. A
script only performs the actions it was written for, so running it again against a changed environment fails or does the
wrong thing. A declarative definition can be applied repeatedly: the engine compares it with recorded state, which makes
previews, review in pull requests and drift detection possible.
| Tool | What you write | What runs |
|---|---|---|
Terraform (OpenTofu) |
HCL with the |
Terraform on your machine or in CI, with state kept in a file or a Cloud Storage bucket |
Infrastructure Manager |
The same Terraform configuration |
Terraform runs managed by Google Cloud, with state kept for you |
Config Connector |
Kubernetes YAML resources |
A controller in a GKE cluster that reconciles the resources continuously |
Deployment Manager |
YAML, Jinja or Python templates |
Google-hosted engine, being shut down (see Deployment Manager shutdown and DM Convert) |
Older guides present Deployment Manager as the native Google Cloud IaC service. It is no longer supported, and the current approach is Terraform, either run by yourself or managed by Infrastructure Manager.
Terraform with the Google provider
Terraform is the most widely used IaC tool for Google Cloud, and the one Google’s own blueprints and tooling target. This page gives only what is needed to follow the rest of the section; in-depth Terraform coverage (modules, workspaces, testing, pipelines) is tracked separately in GitHub issue #171 of this documentation repository and is not repeated here.
Provider configuration and authentication
The hashicorp/google provider (and its sibling google-beta, which exposes Preview features) is configured with a
default project and region. It authenticates with Application Default Credentials, so no service-account key file is
needed: locally use gcloud auth application-default login or impersonate a service account, and in CI use Workload
Identity Federation or an attached service account, see Identity and Access.
gcloud auth application-default login
# or, safer for shared environments: impersonate a deployer service account
export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT="terraform-deployer@my-project-id.iam.gserviceaccount.com"
See the provider reference for the supported authentication options.
Remote state in Cloud Storage
Terraform records what it manages in a state file. Keep it in a versioned Cloud Storage bucket so a team shares one copy
and the gcs backend can lock it during a run. The bucket is created once, outside the configuration it stores state for.
PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
STATE_BUCKET="bookshelf-tfstate-$PROJECT_ID"
gcloud storage buckets create "gs://$STATE_BUCKET" \
--project="$PROJECT_ID" \
--location="$REGION" \
--uniform-bucket-level-access
gcloud storage buckets update "gs://$STATE_BUCKET" --versioning
See Create buckets and Use object versioning.
Terraform workflow
The cycle is terraform init (download providers, connect the backend), terraform plan (preview), terraform apply
and terraform destroy. State can contain sensitive values, so restrict access to the state bucket with IAM.
In the Google Cloud console
The console does not run Terraform itself, but it helps in two ways:
-
Open any resource’s page (for example Cloud Run, then a service), choose the Equivalent code or Equivalent command line option offered by many create forms, and read the generated gcloud or Terraform for what you configured.
-
Use Cloud Shell (the terminal icon at the top right), which has Terraform and the gcloud CLI preinstalled and already authenticated, to run the commands below without installing anything.
With the Terraform CLI: the Bookshelf baseline
The configuration below creates the shared Bookshelf baseline: an Artifact Registry Docker repository bookshelf,
a runtime service account for catalog-api, permission for that account to read the repository, and a Cloud Run service
that starts from Google’s public hello image until the real image is built. Enable the APIs first:
gcloud services enable run.googleapis.com artifactregistry.googleapis.com iam.googleapis.com
Save the following as main.tf:
terraform {
required_version = ">= 1.9"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 8.0"
}
}
backend "gcs" {
bucket = "bookshelf-tfstate-my-project-id" # the state bucket created above
prefix = "bookshelf/baseline"
}
}
variable "project_id" {
type = string
}
variable "region" {
type = string
default = "us-central1"
}
provider "google" {
project = var.project_id
region = var.region
}
resource "google_artifact_registry_repository" "bookshelf" {
repository_id = "bookshelf"
format = "DOCKER"
location = var.region
description = "Bookshelf container images"
}
resource "google_service_account" "catalog_api" {
account_id = "catalog-api"
display_name = "Bookshelf catalog-api runtime"
}
resource "google_artifact_registry_repository_iam_member" "catalog_api_reader" {
repository = google_artifact_registry_repository.bookshelf.name
location = var.region
role = "roles/artifactregistry.reader"
member = "serviceAccount:${google_service_account.catalog_api.email}"
}
resource "google_cloud_run_v2_service" "catalog_api" {
name = "catalog-api"
location = var.region
deletion_protection = false # allow terraform destroy in this sample
template {
service_account = google_service_account.catalog_api.email
containers {
# replace with ${var.region}-docker.pkg.dev/${var.project_id}/bookshelf/catalog-api:TAG
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}
output "catalog_api_url" {
value = google_cloud_run_v2_service.catalog_api.uri
}
Then run:
terraform init
terraform plan -var="project_id=$PROJECT_ID" -out=tfplan
terraform apply tfplan
See google_artifact_registry_repository, google_cloud_run_v2_service and the version 8 upgrade guide. The service is not public: calling it needs an identity token, see Cloud Run.
A reusable Bookshelf module
When more than one environment needs the baseline, wrap the resources above in a module directory
(modules/bookshelf-baseline/ with main.tf, variables.tf and outputs.tf) and call it once per environment with a
different project_id, region and name prefix. Prefer one project per environment, see
Cloud Concepts. Google also publishes ready-made modules; see
Blueprints and Cloud Foundation Fabric.
Infrastructure Manager
Infrastructure Manager (Infra Manager) is a Google Cloud service that runs Terraform for you. You submit a Terraform configuration from a local directory, a Cloud Storage bucket or a Git repository; the service executes it under a service account you choose, stores the state, and records every revision of the deployment. It is the supported replacement for Deployment Manager. A preview shows the plan without changing anything, and a deployment can be locked, updated or deleted as a unit. Check the pricing page for the current model, since it can change.
Roles and service account
Two identities are involved. The person (or pipeline) that runs gcloud infra-manager needs roles/config.admin. The
deployment runs as a service account that needs roles/config.agent plus whatever roles the resources require (here
Artifact Registry admin, Cloud Run admin, service account admin and service account user, or a narrower custom role).
In the Google Cloud console
-
Select the project in the project picker and enable the Infrastructure Manager API.
-
Open Infrastructure Manager from the navigation menu (search for it in the search bar if it is not pinned).
-
Choose Create deployment, enter a name (
bookshelf-baseline) and a region. -
Choose a Terraform source: Git repository or Cloud Storage bucket (local directories are available from the CLI).
-
Pick the service account the deployment runs as, enter input values such as
project_id, and choose Create. -
Use Preview before applying changes, then open the deployment to see its resources, revisions and logs.
With the gcloud CLI
PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
SA=infra-manager-deployer
gcloud services enable config.googleapis.com
gcloud iam service-accounts create "$SA" --display-name="Infrastructure Manager deployer"
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member="serviceAccount:$SA@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/config.agent"
# add the roles the Terraform resources need (Artifact Registry, Cloud Run, IAM)
gcloud infra-manager previews create bookshelf-baseline-preview \
--location="$REGION" \
--service-account="projects/$PROJECT_ID/serviceAccounts/$SA@$PROJECT_ID.iam.gserviceaccount.com" \
--local-source=./bookshelf-baseline \
--input-values="project_id=$PROJECT_ID"
gcloud infra-manager deployments apply bookshelf-baseline \
--location="$REGION" \
--service-account="projects/$PROJECT_ID/serviceAccounts/$SA@$PROJECT_ID.iam.gserviceaccount.com" \
--local-source=./bookshelf-baseline \
--input-values="project_id=$PROJECT_ID"
gcloud infra-manager deployments describe bookshelf-baseline --location="$REGION"
gcloud infra-manager resources list --deployment=bookshelf-baseline --location="$REGION"
See the Infrastructure Manager documentation and the
gcloud infra-manager reference for
the exact flags in your CLI version. Use --git-source-repo, --git-source-directory and --git-source-ref instead of
--local-source to deploy from Git. The configuration given to Infrastructure Manager manages its own state, so remove
the backend "gcs" block from main.tf for this route.
Deployment Manager shutdown and DM Convert
Deployment Manager is the older Google Cloud IaC service (YAML configurations with Jinja or Python templates). Its lifecycle, from the official deprecation notice:
| Date | Milestone |
|---|---|
2026-04-01 |
End of support: no new features or non-critical fixes, and support tickets are only accepted for migration blockers |
2026-06-30 |
New customers can no longer start using the service |
2027-03-31 |
End of extended support for migration blockers |
2027-06-30 |
Shutdown of the service |
Existing deployments keep running until the shutdown, but should be migrated now. Google’s DM Convert tool automates most of the work in three steps: convert the YAML, Jinja or Python configuration to Terraform HCL, import the existing resources into an Infrastructure Manager deployment so they are not recreated, and delete the old Deployment Manager deployment while abandoning (not deleting) its resources. Some Deployment Manager concepts have no direct Terraform equivalent, so expect to review and edit the generated HCL, and run a preview before applying.
The Runtime Configurator API, which stores configuration variables and watchers for Deployment Manager, is part of the same product and goes away with it. Do not adopt it for new work; use Parameter Manager and Secret Manager instead, see Runtime Configuration.
Config Connector
Config Connector lets you manage Google Cloud resources as Kubernetes custom resources. A controller in a GKE cluster
reconciles each resource (StorageBucket, PubSubTopic, ArtifactRegistryRepository, …) against Google Cloud
continuously, so manual drift is corrected automatically. It suits teams that already operate everything through
kubectl and GitOps; for everything else Terraform is simpler. It is available as a GKE add-on.
CLUSTER=bookshelf-gke
REGION=us-central1
gcloud container clusters update "$CLUSTER" \
--location="$REGION" \
--update-addons=ConfigConnector=ENABLED
kubectl annotate namespace default cnrm.cloud.google.com/project-id="$PROJECT_ID"
See Install Config Connector. The controller needs a Google service account bound with Workload Identity Federation for GKE and the roles for the resources it manages. A resource then looks like this:
apiVersion: artifactregistry.cnrm.cloud.google.com/v1beta1
kind: ArtifactRegistryRepository
metadata:
name: bookshelf
spec:
format: DOCKER
location: us-central1
Apply it with kubectl apply -f repository.yaml. See
the resource reference
for its fields.
Blueprints and Cloud Foundation Fabric
Rather than writing everything from scratch, start from vetted modules. The Google Cloud Terraform blueprints and modules cover networks, projects, GKE and more, and the Enterprise foundations blueprint sets up an organization-level landing zone (folders, org policies, shared VPC, logging) with Terraform. Cloud Foundation Fabric is an open-source collection of Terraform modules and end-to-end examples maintained by Google Cloud engineers. Pin module versions, and review what they create before applying them, because they can create billable resources and organization-wide policy. See Terraform blueprints and modules for Google Cloud.
Bootstrapping Terraform from existing resources
For resources that were created by hand, export their configuration rather than rewriting it. gcloud can print many
resources as YAML that mirrors the API representation, and the resource-config command exports Terraform HCL:
gcloud services enable cloudasset.googleapis.com
gcloud components install config-connector
gcloud run services describe catalog-api --region="$REGION" --format=export > catalog-api.yaml
gcloud beta resource-config bulk-export \
--project="$PROJECT_ID" \
--resource-format=terraform \
--resource-types=ArtifactRegistryRepository,StorageBucket \
--path=./exported
See Export your Google Cloud resources into
Terraform format. Export does not support every resource type, is not available on Windows, and the output is a starting
point: review it, remove defaults, then import the resources into state with terraform import or import blocks.
Pricing, quotas and launch stages
Terraform and the provider are free; you pay for the resources they create and for the Cloud Storage bucket that holds state. Infrastructure Manager’s charges and the free allowance are listed on the Infrastructure Manager pricing page, which should be read on the day you plan costs. Config Connector as a GKE add-on is billed through the cluster it runs on. Infrastructure Manager is generally available; its limits (deployments per region, concurrent runs) are in the quotas page, and Terraform runs time out when a single apply takes too long, so split large configurations.
Clean up
Remove resources in the reverse of the order they were created:
# Terraform baseline
terraform destroy -var="project_id=$PROJECT_ID"
# Infrastructure Manager deployment and preview
gcloud infra-manager deployments delete bookshelf-baseline --location="$REGION"
gcloud infra-manager previews delete bookshelf-baseline-preview --location="$REGION"
# Config Connector add-on and resource
kubectl delete -f repository.yaml
gcloud container clusters update "$CLUSTER" --location="$REGION" --update-addons=ConfigConnector=DISABLED
# Deployer service account and state bucket (delete state last, only when nothing uses it)
gcloud projects remove-iam-policy-binding "$PROJECT_ID" \
--member="serviceAccount:infra-manager-deployer@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/config.agent"
gcloud iam service-accounts delete "infra-manager-deployer@$PROJECT_ID.iam.gserviceaccount.com"
gcloud storage rm --recursive "gs://bookshelf-tfstate-$PROJECT_ID"
Delete the state bucket’s versions too (gcloud storage rm --recursive removes all versions of a versioned bucket’s
objects and the bucket). Deleting a throwaway project removes everything at once, after a 30-day recovery window. See
Shutting down projects.