Terraform and OpenTofu on Google Cloud: Getting Started with the Google Provider
Google Cloud with Terraform #
Terraform and OpenTofu manage Google Cloud with the google provider. The workflow is the same as for AWS and Azure. Google Cloud organizes everything in projects.
Authentication #
Install the gcloud CLI and create application default credentials:
$ gcloud auth login
$ gcloud auth application-default login
$ gcloud config set project my-project-id
In CI/CD use workload identity federation with OIDC (the equivalent of OIDC with AWS), not downloaded service account keys.
Provider #
terraform {
required_version = ">= 1.6"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 6.0"
}
}
}
provider "google" {
project = var.project_id
region = var.region
}
variable "project_id" {
type = string
}
variable "region" {
type = string
default = "europe-west1"
}Enable the APIs #
Each Google Cloud service must be enabled in the project before use. Do it with Terraform so that the configuration is complete:
resource "google_project_service" "apis" {
for_each = toset([
"compute.googleapis.com",
"storage.googleapis.com",
])
service = each.key
disable_on_destroy = false
}This uses for_each. Make other resources depend on it (depends_on = [google_project_service.apis]) to avoid errors on the first apply.
A VPC network and a subnet #
resource "google_compute_network" "main" {
name = "ditwl-demo"
auto_create_subnetworks = false
depends_on = [google_project_service.apis]
}
resource "google_compute_subnetwork" "private" {
name = "ditwl-demo-private"
region = var.region
network = google_compute_network.main.id
ip_cidr_range = "10.0.1.0/24"
private_ip_google_access = true
}
resource "google_compute_firewall" "ssh_iap" {
name = "ditwl-demo-allow-ssh-iap"
network = google_compute_network.main.name
allow {
protocol = "tcp"
ports = ["22"]
}
source_ranges = ["35.235.240.0/20"] # Identity-Aware Proxy range
}In Google Cloud a VPC network is global, and subnets are regional. Firewall rules apply at the network level and use tags or service accounts instead of security groups attached to instances.
A Cloud Storage bucket #
resource "google_storage_bucket" "data" {
name = "${var.project_id}-ditwl-data"
location = var.region
uniform_bucket_level_access = true
public_access_prevention = "enforced"
versioning {
enabled = true
}
lifecycle_rule {
condition {
age = 90
}
action {
type = "SetStorageClass"
storage_class = "NEARLINE"
}
}
depends_on = [google_project_service.apis]
}Remote state in GCS #
terraform {
backend "gcs" {
bucket = "my-project-tfstate"
prefix = "demo"
}
}The bucket must exist before init and should have versioning enabled. GCS provides locking. See backends.
Run it #
$ tofu init
$ tofu apply -var project_id=my-project-id
$ tofu destroy -var project_id=my-project-id
Compare with AWS #
| AWS | Google Cloud |
|---|---|
| Account / Organizations | Project / Folders and organization |
| VPC (regional) | VPC network (global) |
| EC2 | Compute Engine |
| S3 | Cloud Storage |
| IAM role | IAM role binding and service accounts |
| KMS | Cloud KMS |
| EKS | GKE |
| Lambda | Cloud Functions / Cloud Run |
Production-ready modules are in the Cloud Foundation Toolkit. Read next project structure and best practices.