# Terraform and OpenTofu on Google Cloud: Getting Started with the Google Provider

> Deploy your first resources on Google Cloud with Terraform or OpenTofu: authentication, enabling APIs, a VPC network, a Cloud Storage bucket and remote state in GCS.

- Source: https://www.itwonderlab.com/terraform-gcp-getting-started/
- Published: 2026-04-15
- Updated: 2026-04-15
- Author: Javier Ruiz Jiménez (https://www.javierruizjimenez.com/)
- Site: IT Wonder Lab (https://www.itwonderlab.com/)

---

## Google Cloud with Terraform

Terraform and OpenTofu manage Google Cloud with the `google` [provider](https://www.itwonderlab.com/terraform-provider/). The workflow is the same as for [AWS](https://www.itwonderlab.com/aws-terraform-tutorial-terraform-basics/) and [Azure](https://www.itwonderlab.com/terraform-azure-getting-started/). Google Cloud organizes everything in **projects**.

### Authentication

Install the [gcloud CLI](https://cloud.google.com/sdk/docs/install) and create application default credentials:

```shell
$ 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](https://www.itwonderlab.com/terraform-github-actions-aws-oidc/)), not downloaded service account keys.

### Provider

```hcl title="providers.tf"
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:

```hcl title="apis.tf"
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`](https://www.itwonderlab.com/terraform-for-each-vs-count/). 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

```hcl title="network.tf"
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

```hcl title="storage.tf"
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

```hcl title="backend.tf"
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](https://www.itwonderlab.com/terraform-backend/).

### Run it

```shell
$ 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](https://www.itwonderlab.com/aws-organizations/) | Project / Folders and organization |
| [VPC](https://www.itwonderlab.com/aws-vpc/) (regional) | VPC network (global) |
| [EC2](https://www.itwonderlab.com/aws-ec2/) | Compute Engine |
| [S3](https://www.itwonderlab.com/aws-s3/) | Cloud Storage |
| [IAM](https://www.itwonderlab.com/aws-iam/) role | IAM role binding and service accounts |
| [KMS](https://www.itwonderlab.com/aws-kms/) | Cloud KMS |
| [EKS](https://www.itwonderlab.com/aws-eks/) | GKE |
| [Lambda](https://www.itwonderlab.com/aws-lambda/) | Cloud Functions / Cloud Run |

Production-ready modules are in the [Cloud Foundation Toolkit](https://cloud.google.com/docs/terraform/blueprints/terraform-blueprints). Read next [project structure](https://www.itwonderlab.com/terraform-project-structure/) and [best practices](https://www.itwonderlab.com/terraform-best-practices/).
