The intersection of Terraform and Google Cloud Platform revolves around identity. Automated deployments cannot rely on an individual Google account for authentication because personal credentials introduce human dependency, audit ambiguity, and security risk. Production Terraform runs require a dedicated machine identity that belongs to the project, carries explicit IAM role bindings, and can be rotated and audited independently. A GCP service account is that identity. It has an email address in the form [email protected], a key pair for authentication, and IAM role bindings that determine its permissions. Service accounts are the standard way to authenticate automated workloads including Terraform, CI/CD pipelines, and applications running on GCP.
When Terraform is used against Google Cloud, the provider must authenticate as that service account. The provisioning workflow typically starts with creating the service account, assigning the minimum necessary roles, and then configuring the Terraform Google provider to use it. The same Terraform configuration can also be used to create the service account itself, which closes the loop: Terraform creates the identity it will use for subsequent runs. This creates a self-reinforcing infrastructure pattern where the service account lifecycle is version controlled, peer reviewed, and applied consistently.
What a GCP Service Account Represents in Terraform Workflows
A GCP service account is a special type of Google account that belongs to your project rather than to an individual user. It is not tied to a person, it persists across team changes, and it can be granted granular permissions through IAM.
The service account object contains:
- An email address like
[email protected] - A key pair for authentication
- IAM role bindings that determine its permissions
The impact of using a service account instead of user credentials is operational continuity. When an engineer leaves the organization, Terraform runs do not break. Audit logs show serviceAccount:terraform@... as the actor rather than a personal email, which improves compliance reporting. The identity can be scoped to a single project or across organizations, and its keys can be rotated without changing provider configuration if environment variables are used.
In the context of Terraform, the service account is both a resource to be created and the principal used to authenticate the provider. This dual role means the configuration must distinguish between creation time and apply time. Creation time requires an initial bootstrap identity, often a user with Project IAM Admin, while apply time uses the service account itself once it exists.
Creating a Service Account with gcloud CLI as Pre-requisite
Before Terraform can manage a service account, the account must exist or be provisioned. The gcloud CLI provides the imperative path for bootstrapping.
Set the project context first:
export PROJECT_ID="my-project-123"
gcloud config set project $PROJECT_ID
Create the service account with a display name and description:
gcloud iam service-accounts create terraform \
--display-name="Terraform Service Account" \
--description="Used by Terraform to manage GCP infrastructure"
Verify creation:
gcloud iam service-accounts list
The display name and description are metadata that surface in the Cloud Console and in IAM audit logs. The account_id terraform becomes part of the email address terraform@PROJECT_ID.iam.gserviceaccount.com. That email is the identifier used in all IAM bindings.
The impact layer for this step is that the service account now exists in GCP but has no permissions. Any Terraform run attempting to use it will fail with permission denied until roles are bound. The contextual layer is that this manual creation is often done once as a bootstrap step, then subsequent Terraform runs manage the account's roles and keys declaratively.
Assigning Roles and IAM Policy Bindings
Granting permissions to the service account is done via IAM policy bindings. The reference facts show two patterns: direct role assignment via gcloud projects add-iam-policy-binding and declarative assignment via google_project_iam_member.
A broad access example for initial setup, not recommended for production:
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:terraform@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/editor"
A more targeted role for Cloud SQL:
--role="roles/cloudsql.admin"
For a general-purpose Terraform service account, the Editor role might be used during initial setup and tightened later. The principle of least privilege should guide final role selection.
The real-world consequence of role assignment is blast radius control. Granting roles/editor allows Terraform to create, modify, and delete almost all resources in the project. In production, this should be replaced with a list of specific roles such as roles/storage.objectViewer and roles/pubsub.publisher.
In Terraform, roles can be defined as a variable for better organization:
variable "roles" {
type = list(string)
default = [
"roles/storage.objectViewer",
"roles/pubsub.publisher",
]
}
And assigned using for_each:
resource "google_project_iam_member" "service_account_roles" {
for_each = toset(var.roles)
role = each.value
member = "serviceAccount:${google_service_account.default.email}"
}
This iterates through the roles list and grants each role to the service account at the project level. The for_each construct allows multiple instances of a resource based on a collection.
Terraform Configuration for Service Account Creation
Terraform can create the service account declaratively. A minimal configuration defines the provider, backend, variables, and the resource.
Create a working directory:
mkdir terraform-service-account && cd $_
Create main.tf:
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 4.0"
}
}
backend "gcs" {
bucket = "qwiklabs-gcp-02-2382fe5fa47a-tf-state"
prefix = "terraform/state"
}
}
provider "google" {
project = var.project_id
region = var.region
}
resource "google_service_account" "default" {
account_id = "terraform-sa"
display_name = "Terraform Service Account"
}
This configuration defines a Google Cloud service account named terraform-sa.
Create variables.tf:
variable "project_id" {
type = string
description = "The GCP project ID"
default = "qwiklabs-gcp-02-2382fe5fa47a"
}
variable "region" {
type = string
description = "The GCP region"
default = "us-central1"
}
Initialize and apply:
terraform init
terraform apply -auto-approve
The terraform init command initializes Terraform in the current directory. The terraform apply -auto-approve command applies the configuration and creates the resource.
The impact of this pattern is repeatability. The service account definition is stored in version control, peer reviewed, and applied consistently across environments. The contextual layer connects to authentication: once the service account exists, Terraform can be reconfigured to use it for subsequent runs.
Resource definition pattern table:
| Resource | Purpose | Key Arguments |
|---|---|---|
| googleserviceaccount | Creates the service account itself | accountid, displayname |
| googleprojectiam_member | Binds roles to members at project level | role, member, for_each |
| googleserviceaccount_key | Creates a key for the service account | serviceaccountid |
Authentication Methods for Terraform Google Provider
There are several ways to authenticate Terraform with the service account.
Method 1 - Service Account Key File
Generate a JSON key and point Terraform at it:
gcloud iam service-accounts keys create terraform-key.json \
--iam-account="terraform@${PROJECT_ID}.iam.gserviceaccount.com"
The file contains private key material - handle it securely:
chmod 600 terraform-key.json
Provider configuration:
provider "google" {
project = var.project_id
region = "us-central1"
credentials = file("terraform-key.json")
}
Or use environment variables:
export GOOGLE_CREDENTIALS=$(cat terraform-key.json)
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/terraform-key.json"
Provider with no credentials in code:
provider "google" {
project = var.project_id
region = "us-central1"
# Reads from GOOGLE_CREDENTIALS or GOOGLE_APPLICATION_CREDENTIALS
}
Important security note: Service account keys are long-lived credentials.
The impact of using key files is that the key becomes a secret that must be stored securely, rotated periodically, and never committed to source control. The contextual layer is that Workload Identity Federation is a more secure alternative for CI/CD, as it avoids long-lived keys.
The reference facts note that you can create a credential configuration file and set the GOOGLE_APPLICATION_CREDENTIALS environment variable to point to it. This approach is more secure than creating a service account key. For instructions on setting up Workload Identity Federation for ADC, see Workload Identity Federation with other clouds.
For Terraform Cloud Storage backends, authentication uses any of the methods described. Terraform lets you configure Cloud Storage as a backend to store Terraform state files. To authenticate to a Cloud Storage backend, use any of the methods described on this page.
Infrastructure Manager Service Account Configuration
Infra Manager executes Terraform using the identity of this service account.
You do not need a service account to view information about Infra Manager deployments.
Before you begin:
- Enable the Infra Manager service.
- Create a service account or identify an existing service account to use with Infra Manager.
Grant access to the service account:
To use Infrastructure Manager to create, update, or delete a deployment, an individual user needs access to the service account. Grant the user the Service Account User roles/iam.serviceAccountUser IAM role for the service account.
Grant permissions for Infra Manager:
To work with Infra Manager, the service account needs the Infra Manager Agent roles/config.agent role.
gcloud projects add-iam-policy-binding INFRA_MANAGER_PROJECT_ID \
--member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
--role="roles/config.agent"
Replace:
INFRAMANAGERPROJECT_ID: The project ID of the project where you're creating deployments.
SERVICEACCOUNTEMAIL: The email of the service account.
Grant read permission for the storage bucket:
You can use a storage bucket to store the Terraform configurations that are deployed by Infra Manager.
The impact of this configuration is that Infra Manager can be used as a managed deployment surface for Terraform without exposing service account keys to developers. The contextual layer connects to the broader pattern of separating the identity used to run Terraform from the identities used to develop it.
Operational Considerations and Security Posture
Service account keys are long-lived credentials. Rotation policy should be enforced. The reference facts emphasize handling key files securely with chmod 600.
When running Terraform in a local development environment, on premises, or a different cloud provider, you can create a service account, grant it the IAM roles that your application requires, and create a key for that service account.
To create a service account key and make it available to ADC:
Create a service account with the roles your application needs, and a key for that service account, by following the instructions in Creating a service account key.
The difference between AWS and GCP service accounts is relevant. AWS uses IAM users and access keys. The reference facts for AWS show creating an admin user group, creating a Terraform user, adding to group, and creating access keys. That pattern maps conceptually to GCP service accounts but uses different primitives.
Conclusion
Terraform provisioning of a GCP service account is a two-phase identity problem. First, the service account must exist and be granted appropriate IAM roles. Second, the Terraform Google provider must authenticate as that service account using a key file, environment variable, or workload identity federation. The reference facts demonstrate both imperative bootstrapping with gcloud and declarative management with Terraform resources such as google_service_account and google_project_iam_member. Role binding can be done inline via gcloud projects add-iam-policy-binding or declaratively via for_each over a roles variable. Authentication choices trade convenience for security, with long-lived service account keys being the simplest but least secure method. For production use, the service account created by Terraform should be minimally privileged, its keys rotated or eliminated in favor of workload identity, and its usage audited through Cloud Audit Logs. The configuration shown in the reference facts provides a complete path from manual creation to fully managed infrastructure as code.
Sources
- How to configure GCP provider with service account
- How to create a service account on AWS for Terraform
- Terraform Essentials Service Account Gem Terraform SA Create
- Terraform GCP Service Account Creation with Roles
- Authenticate using service account keys
- Configure service account for Infrastructure Manager