Terraform GCP Service Account Configuration and Role Binding

Running Terraform against Google Cloud in production means you need a service account. Your personal Google account works fine for experimentation, but automated deployments need a dedicated identity with specific permissions. This guide covers creating a service account, assigning the right roles, and configuring the Terraform Google provider to use it. Service accounts are the foundation of secure Terraform automation on GCP. Create a dedicated service account with the minimum required roles, prefer keyless authentication through Workload Identity Federation or impersonation, and fall back to key files only when necessary. Whichever method you choose, keep credentials out of your Terraform code and use environment variables or the provider's built-in credential chain.

A GCP service account is a special type of Google account that belongs to your project rather than to an individual user. It has an email address like terraform@PROJECT_ID.iam.gserviceaccount.com, 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.

Service Account Creation with gcloud CLI

Using gcloud CLI to create a service account provides direct control before Terraform codifies the resource.

export PROJECT_ID="my-project-123" gcloud config set project $PROJECT_ID

gcloud iam service-accounts create terraform \ --display-name="Terraform Service Account" \ --description="Used by Terraform to manage GCP infrastructure"

Verify it was created:

gcloud iam service-accounts list

The creation command establishes an identity with a display name and description. The email address format is NAME@PROJECTID.iam.gserviceaccount.com. Double-check the email format. It should be NAME@PROJECTID.iam.gserviceaccount.com. Service account does not exist errors commonly trace back to incorrect email formatting.

Impact for users is immediate operational clarity. A dedicated service account isolates Terraform actions from individual user accounts. Audit logs attribute changes to the service account identity rather than a person. This isolation supports least privilege enforcement and simplifies revocation.

Contextually, the gcloud creation step precedes Terraform state. Teams often bootstrap the service account manually once, then import it into Terraform or define it declaratively. The display name and description become metadata for IAM audits and human readability.

Role Assignment and Permission Scoping

Grant the service account the permissions it needs. Roles determine what Terraform can create, read, update, or delete.

gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:terraform@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/editor"

For a general-purpose Terraform service account, you might use the Editor role during initial setup and tighten it later. Broad access for initial setup is not recommended for production.

Specific role examples include:

--role="roles/cloudsql.admin"

Check the error message for the specific permission needed. List current roles:

gcloud projects get-iam-policy $PROJECT_ID \ --flatten="bindings[].members" \ --filter="bindings.members:terraform@${PROJECT_ID}.iam.gserviceaccount.com" \ --format="table(bindings.role)"

If the output shows missing permissions, add the precise role instead of expanding to Editor.

Impact layer: Over-privileged service accounts increase blast radius. A compromised key can be used to modify billing, storage, or compute resources across the project. Tightening roles after initial setup reduces long-term risk.

Contextual layer: Role assignment is separate from service account creation. The same service account can receive different roles per project via project-level bindings. This allows reuse of one identity across multiple projects with scoped permissions.

API Enablement Prerequisites

GCP requires you to enable APIs before using them. Terraform plans that reference a service will fail with "API not enabled" if the API is not activated in the project.

gcloud services enable compute.googleapis.com gcloud services enable container.googleapis.com gcloud services enable sqladmin.googleapis.com gcloud services enable storage.googleapis.com

The error message "API not enabled" appears in Terraform runs when a required service is not activated. Enabling APIs is a prerequisite step that must occur before resources are created.

Impact for users is failed applies. A plan may succeed but apply fails at resource creation time, causing partial state.

Contextual layer: API enablement is project-wide. The service account must also have roles that permit the API usage. Both conditions must be satisfied.

Authentication Methods for Terraform 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.tf

provider "google" { project = var.project_id region = "us-central1" credentials = file("terraform-key.json") }

Or better, use the GOOGLE_CREDENTIALS environment variable:

export GOOGLE_CREDENTIALS=$(cat terraform-key.json)

Or point to the file path

export GOOGLE_APPLICATION_CREDENTIALS="/path/to/terraform-key.json"

provider.tf - no credentials in code

```
provider "google" {
project = var.project_id
region = "us-central1"

Reads from GOOGLECREDENTIALS or GOOGLEAPPLICATION_CREDENTIALS

}
```

Important security note: Service account keys are long-lived credentials. Long-lived keys increase exposure window if leaked. Rotate keys regularly and avoid committing them to version control.

Impact: Using environment variables keeps credentials out of Terraform code. This prevents secret leakage in repositories and allows different credentials per execution environment.

Contextually, the provider's credential chain falls back to Application Default Credentials when no explicit credentials are set. Explicit configuration is preferred for reproducibility.

Terraform Declarative Service Account Definition

To create a GCP service account with roles using Terraform, you'll generally follow these steps:

Define the service account:

resource "google_service_account" "default" { account_id = "your-service-account-id" display_name = "Your Service Account Name" }

Replace "your-service-account-id" with a unique identifier for your service account. Replace "Your Service Account Name" with a descriptive name.

Define the roles:

variable "roles" { type = list(string) default = [ "roles/storage.objectViewer", "roles/pubsub.publisher", ] }

Assign roles using googleprojectiam_member:

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.

Explanation:

googleserviceaccount: This resource creates the service account itself.

googleprojectiam_member: This resource binds roles to members at the project level.

for_each: This Terraform construct allows you to create multiple instances of a resource based on a collection.

This table summarizes key aspects:

Feature | Description | Terraform Resource | Example
Service Account Creation | Defines the service account with a unique ID and display name. | googleserviceaccount | resource "googleserviceaccount" "default" { accountid = "your-service-account-id" displayname = "Your Service Account Name" }
Role Definition | Specifies the roles to be assigned, either directly or using variables for better organization

Impact: Declarative definition enables version control, peer review, and repeatable deployments. Changing roles in code triggers a plan that shows exact permission changes.

Contextual layer: The googleprojectiammember resource uses the service account email output from googleservice_account.default.email. This creates an implicit dependency and ensures correct ordering.

Troubleshooting and Operational Notes

IAM Propagation Delays: Be aware that IAM changes might take a few minutes to propagate fully. If you encounter permission issues immediately after creating or modifying a service account, wait a short period and try again.

Error Messages: Pay close attention to Terraform error messages, as they often provide valuable clues for resolving issues related to service account creation or role assignment.

This helps with troubleshooting and security audits.

Alternatives:

Workload Identity Federation: For applications running outside of GCP, consider using Workload Identity Federation to grant them temporary credentials to access GCP resources without needing a service account key.

Terraform Google Provider Documentation: Refer to the official Terraform Google provider documentation for the most up-to-date information on resources and their usage: https://registry.terraform.io/providers/hashicorp/google/latest/docs

Prefer keyless authentication through Workload Identity Federation or impersonation, and fall back to key files only when necessary.

Cross-Project Service Account Token Creator Role

In Infrastructure Manager contexts, service account email formation follows a pattern:

service-INFRAMANAGER[email protected]

This forms the email ID of the service agent.

Grant the Service Account Token Creator (roles/iam.serviceAccountTokenCreator) role to the Cloud Build service agent in the project where you're creating deployments. To allow Infra Manager to execute Terraform using Cloud Build, the Cloud Build service agent in the project containing the service account needs additional permissions as part of the cross-project set up:

gcloud projects add-iam-policy-binding SERVICE_ACCOUNT_PROJECT_ID \ --member="serviceAccount:service-INFRA_MANAGER_PROJECT_NUMBER@gcp-sa-cloudbuild.iam.gserviceaccount.com" \ --role="roles/iam.serviceAccountTokenCreator"

What's next includes learning about IAM, learning more about Terraform with Google Cloud, deploying infrastructure using Infra Manager, updating a deployment, and viewing the state of a deployment.

Impact: Cross-project bindings enable secure delegation without sharing keys. The Token Creator role allows one service agent to mint short-lived tokens for another service account.

Contextual layer: This pattern appears when Terraform runs are executed by Cloud Build on behalf of Infra Manager. The service account in the target project must be accessible via token creation rather than static keys.

Summary of Security Practice

Service accounts are the foundation of secure Terraform automation on GCP. Create a dedicated service account with the minimum required roles, prefer keyless authentication through Workload Identity Federation or impersonation, and fall back to key files only when necessary. Whichever method you choose, keep credentials out of your Terraform code and use environment variables or the provider's built-in credential chain.

The example code includes explanations and important considerations for managing service accounts and their permissions effectively. This guide explains how to create a Google Cloud Platform service account and assign it roles using Terraform. We'll cover defining the service account, specifying roles, and using the googleprojectiam_member resource to grant the roles.

Conclusion

Service account lifecycle for Terraform on GCP spans creation, role binding, authentication configuration, and ongoing maintenance. gcloud CLI provides immediate bootstrapping for initial setup, while Terraform resources googleserviceaccount and googleprojectiammember codify the identity and permissions in versioned infrastructure code. Authentication choices range from long-lived JSON key files managed via GOOGLECREDENTIALS or GOOGLEAPPLICATIONCREDENTIALS environment variables to preferred keyless methods like Workload Identity Federation and impersonation.

Operational stability depends on handling IAM propagation delays, enabling required APIs before resource creation, and interpreting Terraform error messages for missing permissions. Cross-project scenarios such as Infrastructure Manager with Cloud Build require explicit Service Account Token Creator grants to allow token minting without key exchange. Keeping credentials out of code, using for_each for role iteration, and defining roles via variables supports auditability and least privilege. These practices together form a consistent, auditable pattern for Terraform automation on Google Cloud.

Sources

  1. https://oneuptime.com/blog/post/2026-02-23-how-to-configure-gcp-provider-with-service-account/view
  2. https://nulldog.com/terraform-gcp-service-account-creation-with-roles
  3. https://docs.cloud.google.com/infrastructure-manager/docs/configure-service-account

Related Posts