Terraform

Terraform google Provider Practical Guide: Common GCP Setups and Associate Exam Prep

2026-04-19
NicheeLab Editorial Team

When you start managing GCP with Terraform, the first stumbling block is usually the basic configuration of the google provider. Handling authentication, the precedence of project/region/zone, passing providers between modules, protecting state, enabling APIs, and specifying the billing project are all topics that come up often in both real-world work and the exam.

This article walks through the most common settings at the Terraform Associate level, focusing on stable, officially documented behavior so you can put together a safe baseline as quickly as possible.

Authentication Basics: ADC vs. Service Account Keys vs. Impersonation

The first decision is how you authenticate. Terraform's google provider prefers Application Default Credentials (ADC). For local development, use gcloud auth application-default login; for CI/CD, short-lived service account tokens or impersonation (impersonate_service_account) are the solid choices.

Long-lived JSON keys carry a high management burden and leak risk, so avoid them when you can. Even if your current workflow still requires key files, you should have a plan to migrate to impersonation or federated identity (e.g., Workload Identity Federation).

  • Resolution order: explicit settings and environment variables are resolved before ADC
  • GOOGLE_APPLICATION_CREDENTIALS is a convenient local option; prefer short-lived credentials in CI
  • impersonate_service_account requires no key file and makes least-privilege easier to enforce
  • Avoid passing access_token directly when possible — refresh and expiration are hard to manage
Authentication methodCharacteristics / when to useExam notes
ADC (Application Default Credentials)Convenient for local development and gcloud integration; reduces environment-specific configUnderstand ADC's discovery order and its relationship with GOOGLE_APPLICATION_CREDENTIALS
JSON key (service account key file)Usable directly from your machine or CI, but key management is a heavy burdenLeak risk and rotation overhead — prefer alternatives where possible
Impersonation (impersonate_service_account)No key file required, easy to swap effective permissions, and strong audit storyAvailable as a provider field; be aware of the IAM permission requirements

GCP authentication flow with Terraform (conceptual diagram)

terraform (CLI)ADC / key / impersonationgoogle ProviderGCP APIsIAM / Compute / BQOAuth2 / SA token

Minimal configuration and impersonation example

# ベース: 環境変数やADCで認証を解決する前提
provider "google" {
  project = var.project
  region  = var.region
  zone    = var.zone
}

# インパーソネーションを使う例(CI/CDで推奨されやすい)
provider "google" {
  project                    = var.project
  region                     = var.region
  impersonate_service_account = var.impersonated_sa_email
  # 必要に応じ request_timeout 等の基本チューニングも可能
  # request_timeout = "60s"
}

variable "project" {}
variable "region"  { default = "us-central1" }
variable "zone"    { default = "us-central1-a" }
variable "impersonated_sa_email" { default = null }

project/region/zone Precedence and Design

When you set project/region/zone on the google provider, most resources inherit those defaults. However, when an individual resource can specify location/region/zone directly, the resource-level setting takes precedence. Across module boundaries, pass these values as input variables to avoid unintentionally mixing regions.

Compute zonal resources (e.g., google_compute_instance) and regional resources (e.g., google_compute_subnetwork) require different levels of granularity. Data analytics services that take a location (BigQuery, GCS) can be set to a multi-region, and they do not need to match the provider's region.

  • Basic precedence: explicit settings on the resource override the provider default
  • Pass project/region/zone explicitly between modules to avoid implicit dependencies
  • Separate naming conventions and tfvars per environment so mismatches are easy to spot

Example: overriding location/region/zone per resource

# provider側のデフォルト
provider "google" {
  project = var.project
  region  = "us-central1"
  zone    = "us-central1-a"
}

# ゾーン資源(デフォルトを継承)
resource "google_compute_instance" "vm" {
  name         = "app-1"
  machine_type = "e2-medium"
  boot_disk { initialize_params { image = "debian-cloud/debian-12" } }
  network_interface { network = "default" }
}

# リージョン資源(providerのregionを継承)
resource "google_compute_address" "addr" {
  name   = "app-addr"
}

# 明示的に別リージョンへ配置
resource "google_compute_subnetwork" "subnet_eu" {
  name          = "app-subnet-eu"
  ip_cidr_range = "10.10.0.0/24"
  region        = "europe-west1"  # providerのregionを上書き
  network       = "default"
}

Safely Managing Multiple Projects with alias

When your stack spans multiple GCP projects (audit, shared infrastructure, etc.), use provider aliases. Bind each alias to a specific project and authentication (impersonation if needed), and pass the corresponding aliases into modules via the providers map.

When a module uses multiple providers internally, use the provider meta-argument to make the alias explicit on each resource. This prevents accidentally deploying to the wrong project.

  • Name aliases by role for clarity: audit, shared, prod, and so on
  • Always pass providers through the providers map at module boundaries
  • Even for the same resource type you can pin to provider = google.audit explicitly

Defining aliases and passing them to modules

# 2つのプロジェクトを操作する例
provider "google" {
  alias   = "app"
  project = var.app_project
  region  = var.region
}

provider "google" {
  alias   = "audit"
  project = var.audit_project
  region  = var.region
  impersonate_service_account = var.audit_impersonated_sa
}

module "network" {
  source = "./modules/network"
  # モジュール内で `provider = google.audit` を使うリソースがある想定
  providers = {
    google        = google.app
    google.audit  = google.audit
  }
  project_app   = var.app_project
  project_audit = var.audit_project
}

variable "app_project" {}
variable "audit_project" {}
variable "region" { default = "us-central1" }
variable "audit_impersonated_sa" { default = null }

Protecting State and Basic Setup with the GCS Backend

Terraform state must be shared across the team and protected from concurrent runs. The GCS backend provides basic consistency through bucket generation versioning and atomic writes. You do not need an external lock like DynamoDB, but you should still limit CI job concurrency.

At a minimum, enable object versioning on the GCS bucket and set appropriate IAM (viewer for read, admin for write). Splitting prefixes per environment makes restores and rollbacks easier.

  • Enabling bucket versioning is a non-negotiable in production
  • Separate prefixes per environment or workspace
  • Minimum service account permissions: roughly storage.objects.get/compose/update

Basic GCS backend example

terraform {
  backend "gcs" {
    bucket = "my-tfstate-bucket"
    prefix = "envs/prod"
  }
  required_version = ">= 1.5.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 5.0"
    }
  }
}

# バケット側は別途作成し、バージョニングを有効化しておく

API Enablement, Dependencies, and the Basics of Retries/Timeouts

Most GCP services require API enablement. Enable APIs first via google_project_service and make downstream resources explicitly depend on them. Just after the first enablement, internal propagation can take a while, so plan/apply retries and timeout tuning help.

request_timeout on the provider is useful for raising the overall ceiling on API calls. Keep your resource definitions idempotent and control order with depends_on so that re-runs after failures stay safe.

  • Enable APIs explicitly with google_project_service before creating dependent resources
  • Tune request_timeout to absorb propagation delay after first-time API enablement
  • Use for_each to enable multiple APIs at once and avoid missing any

Example: API enablement and dependencies

locals {
  required_apis = [
    "compute.googleapis.com",
    "iam.googleapis.com",
    "cloudresourcemanager.googleapis.com"
  ]
}

resource "google_project_service" "enable" {
  for_each           = toset(local.required_apis)
  project            = var.project
  service            = each.key
  disable_on_destroy = false
}

resource "google_service_account" "deployer" {
  project      = var.project
  account_id   = "deployer"
  display_name = "Deployer SA"
  depends_on   = [google_project_service.enable]
}

provider "google" {
  project         = var.project
  request_timeout = "60s"
}

When to Use billing_project and user_project_override

Some APIs require quota and billing to be attributed to a different project. Set billing_project on the google provider to the billing target, and if needed flip user_project_override to true, to direct billing and quota consumption to the specified project.

These are not required for every API. Leaving them unset is fine unless you have a specific need, but they are useful when you want to consolidate billing in an audit or shared project.

  • billing_project controls who billing and quota are attributed to
  • user_project_override forces user-project billing
  • Don't set them when you don't need to — the default is the safe choice

Example: setting billing_project and user_project_override

provider "google" {
  project              = var.project
  region               = var.region
  billing_project      = var.billing_project
  user_project_override = true
}

variable "project" {}
variable "region" { default = "us-central1" }
variable "billing_project" { default = null }

Check Your Understanding

Associate

問題 1

You want to safely create Terraform-managed resources that span multiple GCP projects. You need to clearly separate an audit project from an application project and prevent misuse inside modules. Which is the most appropriate Associate-level best practice?

  1. Define provider aliases and pass each alias through the module's providers map
  2. Just define two project IDs in terraform.tfvars — Terraform will switch between them automatically
  3. Use a single provider and override project with a var each time; do not use aliases
  4. Use the google-beta provider — it routes resources to the right project automatically

正解: A

For multi-project setups, the safe and repeatable approach is to use provider aliases and pass them explicitly through the providers map to modules. Defining multiple project IDs in tfvars or using google-beta does not automate project segregation.

Frequently Asked Questions

Which takes precedence: GOOGLE_APPLICATION_CREDENTIALS or ADC?

GOOGLE_APPLICATION_CREDENTIALS is consulted as part of ADC's discovery chain, so if it is set, ADC will use it. However, if you explicitly set credentials or impersonate_service_account on the provider block, those explicit settings take precedence.

When should I use google vs. google-beta?

The google provider targets stable APIs, while google-beta includes beta API features. For production and for the exam, prefer the google provider for its stability, and only use google-beta scoped to specific resources when a feature is only available in beta.

Does the GCS backend require a lock table?

No. The GCS backend guarantees consistency through object generation versioning and atomic writes. No external lock table is required, but you should still serialize CI jobs to avoid concurrent applies.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Terraform

HCL Syntax: Terraform's Configuration Language (2026)

HCL2 fundamentals for Terraform — blocks, attributes, expres...

Terraform

Terraform Authoring & Operations Pro: Complete Guide (2026)

Tactics for the Terraform Pro exam — module authoring, works...

Terraform

Terraform Providers: Plugin Management Fundamentals (2026)

Provider mechanics — required_providers, versions, mirrors, ...

Terraform

Terraform Resource Blocks: Declarative Infra Units (2026)

Resource block fundamentals — addresses, references, common ...

Terraform

Terraform Data Sources: Read-Only External Data (2026)

Data source basics — declaration, refresh behavior, dependen...

Browse all Terraform articles (102)
© 2026 NicheeLab All rights reserved.