Terraform’s Google provider can authenticate using either a service account key file or Application Default Credentials (ADC), and understanding the nuances of each is key to managing your cloud resources securely and efficiently.
Let’s see it in action. Imagine you’re setting up a new GCE instance.
provider "google" {
project = "my-gcp-project-12345"
region = "us-central1"
}
resource "google_compute_instance" "default" {
name = "tf-example-instance"
machine_type = "e2-medium"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = "default"
access_config {
// Ephemeral IP
}
}
}
When you run terraform apply, the provider needs to talk to the Google Cloud API. It needs to prove its identity. This is where service accounts and ADC come into play.
The most common way to authenticate is by explicitly providing a service account key. You create a service account in GCP, grant it the necessary roles (like roles/compute.admin for managing Compute Engine resources), and then download its JSON key file. In your Terraform configuration, you’d specify this like so:
provider "google" {
credentials = file("path/to/your/service-account-key.json")
project = "my-gcp-project-12345"
region = "us-central1"
}
Here, credentials = file("path/to/your/service-account-key.json") tells the provider to load the authentication token from that specific JSON file. This is great for CI/CD pipelines or environments where you have a dedicated, long-lived service account for Terraform. The credentials argument expects the content of the JSON key file, which file() function conveniently reads for you. This method is explicit and auditable, as you know exactly which service account is being used.
Application Default Credentials (ADC) is another powerful authentication method. Instead of a key file, ADC relies on a set of well-defined locations where it looks for credentials. The most common ADC scenario for Terraform users is gcloud auth application-default login. When you run this command on your local machine, gcloud creates a credential file that the Google Cloud client libraries (which the Terraform provider uses under the hood) can automatically discover.
If you’ve run gcloud auth application-default login, you might not need to specify credentials or impersonated_service_account in your provider block at all. The provider will automatically pick up your ADC. This is incredibly convenient for local development. The order of discovery for ADC is:
GOOGLE_APPLICATION_CREDENTIALSenvironment variable: If set, it points to a service account key file.gcloudCLI: If you’ve rungcloud auth application-default login, it uses the credentials created by that command.- Compute Engine/App Engine/Cloud Functions metadata server: If running on GCP infrastructure, it can use the attached service account.
This automatic discovery makes ADC flexible. You can switch between authenticating as your user account (via gcloud login) and a service account (via GOOGLE_APPLICATION_CREDENTIALS) without changing your Terraform code, just by changing your environment.
A more advanced pattern is service account impersonation. Instead of giving Terraform a service account key directly, you can have Terraform authenticate as a different service account (often a less-privileged one, like a Workload Identity pool identity) and then impersonate a target service account that has the necessary permissions. This is configured using the impersonated_service_account argument:
provider "google" {
project = "my-gcp-project-12345"
region = "us-central1"
# Assumes ADC is configured to authenticate as a service account
# that has the 'roles/iam.serviceAccountTokenCreator' role
# on the 'target-sa@my-gcp-project-12345.iam.gserviceaccount.com'
impersonated_service_account = "target-sa@my-gcp-project-12345.iam.gserviceaccount.com"
}
This is a best practice for enhanced security. The "identity" running Terraform (whether it’s your local machine via ADC or a CI/CD runner’s service account) only needs permission to act as the target-sa. The target-sa itself then holds the permissions to manage resources. This minimizes the exposure of highly privileged service account keys. The impersonated_service_account value must be the full email address of the service account to impersonate.
When using impersonation, the underlying credentials (ADC or a key file pointed to by GOOGLE_APPLICATION_CREDENTIALS) must have the roles/iam.serviceAccountTokenCreator role on the impersonated_service_account. This allows the underlying identity to generate short-lived credentials for the impersonated service account.
The provider will try to authenticate in a specific order. If you provide credentials, it uses that. If not, it looks for GOOGLE_APPLICATION_CREDENTIALS. If neither is found, it falls back to ADC (which includes gcloud and the metadata server). If impersonated_service_account is set, the initial authentication method is still determined by the above steps, but the resulting token will be for the impersonated service account.
The most surprising thing about ADC is how it gracefully handles environments. If you’re running Terraform on GKE with Workload Identity, or on Cloud Run, or even locally after gcloud auth application-default login, you often don’t need to touch any Terraform provider configuration. The system just knows how to find credentials. This makes it incredibly portable across different execution contexts without requiring code changes.
The next thing you’ll likely encounter is managing multiple GCP projects within a single Terraform configuration, which involves understanding how the project argument interacts with your chosen authentication method.