Terraform + GCP Authentication
Prerequisites
# Terraform is already installed — verify
terraform version
# ADC is a separate login from gcloud CLI login
gcloud auth application-default login # opens browser
# Verify ADC is working
gcloud auth application-default print-access-token
gcloud auth login≠gcloud auth application-default login. The first is for the CLI only. Terraform uses ADC — you need both.
ADC scope
ADC is scoped to a Google Account (user identity), not to a project or org.
~/.config/gcloud/application_default_credentials.json
└── authenticates as: you@gmail.com
└── can reach: any project/folder/org your account has IAM on
One login → access to all projects where your account has permissions. The project in the Terraform provider block is just "where to create resources" — it does not affect credentials.
gcloud auth application-default login
│
▼
your Google Account identity
│
┌───────────┼───────────┐
▼ ▼ ▼
project-A project-B project-C ← all accessible via IAM
When you need multiple credential files
| Situation | Solution |
|---|---|
| Same user, multiple projects | One ADC file — change project in provider |
| Same user, multiple orgs | One ADC file — IAM bindings per org |
| Act as a SA (no key) | One ADC file + impersonate_service_account in provider |
| Act as a SA (with key) | GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json |
| Different Google users | Re-run application-default login (overwrites the file) |
ADC credential expiry
ADC user credentials use OAuth2 refresh tokens:
| Token | Lifetime |
|---|---|
| Access token | ~1 hour — auto-refreshed transparently |
| Refresh token | Long-lived (years) — invalidated only on revocation |
You never need to re-login under normal use. The refresh token is invalidated if you revoke access, change your Google password, or an admin forces session expiry.
Option A — Multiple projects, one login
Same user account, different project per provider alias. Works out of the box with one ADC login.
terraform {
required_providers {
google = { source = "hashicorp/google", version = "~> 6.0" }
}
}
provider "google" {
alias = "dev"
project = "praxedo-dev"
region = "europe-west1"
}
provider "google" {
alias = "prod"
project = "praxedo-prod"
region = "europe-west1"
}
Reference the right provider per resource:
resource "google_storage_bucket" "raw" {
provider = google.dev
name = "raw-lake-dev"
location = "EU"
}
Option B — SA key file (avoid where possible)
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa-key.json
terraform apply
Key files on disk are a security risk. Prefer impersonation (Option C) instead.
Option C — SA impersonation (recommended for production)
No key file. Your ADC user token calls the Token Creator API → gets a short-lived SA token → Terraform uses that SA token for all API calls.
your user (ADC) → impersonates → terraform-sa → acts on → project resources
Setup
Step 1 — Create the SA and grant it roles on the target project:
gcloud iam service-accounts create terraform-sa \
--project=MY_PROJECT \
--display-name="Terraform deployer"
gcloud projects add-iam-policy-binding MY_PROJECT \
--member="serviceAccount:terraform-sa@MY_PROJECT.iam.gserviceaccount.com" \
--role="roles/editor"
Step 2 — Grant your user the right to impersonate it (binding ON the SA as a resource):
gcloud iam service-accounts add-iam-policy-binding \
terraform-sa@MY_PROJECT.iam.gserviceaccount.com \
--member="user:you@gmail.com" \
--role="roles/iam.serviceAccountTokenCreator"
Step 3 — Terraform provider config:
provider "google" {
impersonate_service_account = "terraform-sa@MY_PROJECT.iam.gserviceaccount.com"
project = "MY_PROJECT"
region = "europe-west1"
}
Why this is the right pattern for multi-env setups
| Direct ADC user | SA impersonation | |
|---|---|---|
| Key file on disk | No | No |
| Blast radius if session leaked | Your full account | Only this SA's permissions |
| Audit trail | Your personal user | terraform-sa — clean separation |
| Per-environment scoping | Not possible | Yes — one SA per env |
| Revoke access | Revoke your whole session | Remove the TokenCreator binding |
For a multi-environment Praxedo setup:
terraform-sa-dev@praxedo-dev.iam.gserviceaccount.com → roles scoped to dev
terraform-sa-prod@praxedo-prod.iam.gserviceaccount.com → roles scoped to prod
quota_project_id in ADC
When ADC is configured, GCP sets a quota_project_id in the credentials file. This is the project used for API quota tracking and billing — it is not the project where resources are deployed.
# Change it without re-authenticating
gcloud auth application-default set-quota-project MY_PROJECT
It must point to a billing-enabled project. For local dev your personal project is fine.