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.
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).
| Authentication method | Characteristics / when to use | Exam notes |
|---|---|---|
| ADC (Application Default Credentials) | Convenient for local development and gcloud integration; reduces environment-specific config | Understand 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 burden | Leak risk and rotation overhead — prefer alternatives where possible |
| Impersonation (impersonate_service_account) | No key file required, easy to swap effective permissions, and strong audit story | Available as a provider field; be aware of the IAM permission requirements |
GCP authentication flow with Terraform (conceptual diagram)
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 }
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.
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"
}
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.
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 }
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.
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"
}
}
}
# バケット側は別途作成し、バージョニングを有効化しておく
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.
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"
}
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.
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 }
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?
正解: 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.
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.
Practice with certification-focused question sets
無料で問題を解いてみる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.
HCL Syntax: Terraform's Configuration Language (2026)
HCL2 fundamentals for Terraform — blocks, attributes, expres...
Terraform Authoring & Operations Pro: Complete Guide (2026)
Tactics for the Terraform Pro exam — module authoring, works...
Terraform Providers: Plugin Management Fundamentals (2026)
Provider mechanics — required_providers, versions, mirrors, ...
Terraform Resource Blocks: Declarative Infra Units (2026)
Resource block fundamentals — addresses, references, common ...
Terraform Data Sources: Read-Only External Data (2026)
Data source basics — declaration, refresh behavior, dependen...