Skip to content
Infrastructure as Code iac providers 4 min read

The Google Cloud Provider

The google provider lets Terraform manage Google Cloud Platform resources — from GCS buckets and Compute Engine instances to GKE clusters and BigQuery datasets. Unlike some clouds, GCP work always revolves around a project, and most resources also need a default region and zone. This page covers declaring the provider, the three common ways it authenticates, and a worked example that provisions real infrastructure. Everything here works identically under Terraform 1.5+ and OpenTofu.

Declaring the provider

Pin the provider in a required_providers block so builds are reproducible across machines and CI. The provider is published under the official hashicorp/google namespace. GCP also offers a google-beta provider for preview features; the two are configured the same way and are frequently used side by side via aliases.

terraform {
  required_version = ">= 1.5"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 6.0"
    }
  }
}

provider "google" {
  project = "my-app-prod-4821"
  region  = "us-central1"
  zone    = "us-central1-a"
}

The ~> 6.0 constraint allows minor and patch upgrades (6.1, 6.2, …) but blocks the breaking 7.x major version. Run terraform init to download the plugin and record the resolved version in .terraform.lock.hcl.

Configuration options

The provider "google" block accepts many arguments. The ones you will reach for most are below.

ArgumentPurpose
projectDefault GCP project ID for all resources. Required (or via GOOGLE_PROJECT).
regionDefault region, e.g. europe-west1. Used by regional resources.
zoneDefault zone, e.g. europe-west1-b. Used by zonal resources like VMs.
credentialsPath to (or contents of) a service account key JSON file.
impersonate_service_accountEmail of a service account to impersonate.
user_project_overrideBill quota/API usage to the resource’s project.

Authentication

Terraform resolves Google credentials in a defined order; the first method it finds wins.

For local development the cleanest approach is Application Default Credentials (ADC). You authenticate once with the gcloud CLI, and Terraform automatically picks up the resulting credentials — no keys in your configuration or environment.

gcloud auth application-default login
gcloud config set project my-app-prod-4821

Output:

Credentials saved to file:
[/home/dev/.config/gcloud/application_default_credentials.json]

These credentials will be used by any library that requests
Application Default Credentials (ADC).

With ADC in place, the provider block needs nothing but project, region, and zone.

Service account key

In CI or on a machine where interactive login is impossible, point the provider at a service account key. Prefer supplying it through the environment rather than committing a path into HCL.

export GOOGLE_CREDENTIALS="$(cat terraform-deployer-key.json)"
export GOOGLE_PROJECT="my-app-prod-4821"

If you must reference it in HCL, read the file rather than pasting the JSON inline:

provider "google" {
  project     = "my-app-prod-4821"
  region      = "us-central1"
  credentials = file("terraform-deployer-key.json")
}

Warning: Never commit a service account key file to version control. Add *-key.json to .gitignore, and prefer Workload Identity Federation or service account impersonation over long-lived keys wherever possible.

Service account impersonation

A keyless alternative: authenticate as yourself (or as a Workload Identity in CI), then impersonate a deployer service account. This keeps the powerful permissions on the service account while leaving no key material on disk.

provider "google" {
  project                     = "my-app-prod-4821"
  region                      = "us-central1"
  impersonate_service_account = "[email protected]"
}

Worked example: a GCS bucket and a VM

This configuration creates a versioned Cloud Storage bucket and a small Compute Engine instance, then exports useful attributes. It assumes you have authenticated via ADC.

resource "google_storage_bucket" "assets" {
  name                        = "my-app-prod-assets-4821"
  location                    = "US"
  force_destroy               = false
  uniform_bucket_level_access = true

  versioning {
    enabled = true
  }

  lifecycle_rule {
    condition {
      age = 90
    }
    action {
      type = "Delete"
    }
  }
}

resource "google_compute_instance" "web" {
  name         = "web-1"
  machine_type = "e2-small"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
      size  = 20
    }
  }

  network_interface {
    network = "default"
    access_config {} # ephemeral public IP
  }

  labels = {
    environment = "prod"
    managed_by  = "terraform"
  }
}

output "bucket_url" {
  value = google_storage_bucket.assets.url
}

output "instance_ip" {
  value = google_compute_instance.web.network_interface[0].access_config[0].nat_ip
}

Running terraform apply provisions both resources:

Output:

google_storage_bucket.assets: Creating...
google_storage_bucket.assets: Creation complete after 2s [id=my-app-prod-assets-4821]
google_compute_instance.web: Creating...
google_compute_instance.web: Still creating... [10s elapsed]
google_compute_instance.web: Creation complete after 24s [id=projects/my-app-prod-4821/zones/us-central1-a/instances/web-1]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

bucket_url  = "gs://my-app-prod-assets-4821"
instance_ip = "34.123.45.67"

Querying existing resources

Data sources read infrastructure you do not manage. A common pattern is fetching project metadata or an existing network so new resources can attach to it.

data "google_project" "current" {}

data "google_compute_network" "default" {
  name = "default"
}

output "project_number" {
  value = data.google_project.current.number
}

Best Practices

  • Always pin required_providers with a ~> constraint and commit .terraform.lock.hcl so every environment resolves the same plugin version.
  • Prefer ADC locally and Workload Identity Federation or impersonation in CI — avoid long-lived service account key files.
  • Set project, region, and zone defaults on the provider, and only override them per-resource when a workload genuinely needs a different location.
  • Enable uniform_bucket_level_access on storage buckets to manage permissions with IAM rather than legacy ACLs.
  • Use labels consistently (environment, team, managed_by) so cost reports and inventory tooling can group resources.
  • Enable the required GCP APIs (Compute, Storage, etc.) ahead of time with google_project_service, since resource creation fails if an API is disabled.
Last updated June 14, 2026
Was this helpful?