Introduction
Terraform operations against Google Cloud Platform require a stable identity that is separate from individual user accounts and that can be granted precise IAM permissions. A GCP service account is a special type of Google account that belongs to a project rather than to an individual user. It has an email address, 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. The terraform-google-service-accounts module is a Terraform infrastructure-as-code solution for creating and managing GCP service accounts with associated IAM role bindings. The module automates the provisioning of service accounts, assignment of IAM roles at multiple scopes, optional key generation, and includes specialized submodules for simplified single-account creation and secure key distribution. The module is maintained as part of the Cloud Foundation Toolkit and follows Google Cloud best practices for infrastructure management. The repository implements a modular architecture with three distinct entry points, each serving different service account management workflows. The root module uses Terraform's for_each meta-argument to manage multiple service accounts and their IAM bindings. Running Terraform against Google Cloud in production means you need a service account. Personal Google accounts work 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.
Terraform Google Service Accounts Module Overview
The terraform-google-service-accounts module provides a declarative interface for the operational overhead of managing GCP service accounts. The module automates provisioning of service accounts, assignment of IAM roles at multiple scopes, optional key generation, and includes specialized submodules for simplified single-account creation and secure key distribution.
The module addresses the operational overhead of managing GCP service accounts by providing a declarative interface for creating and managing service accounts and IAM bindings. The module is maintained as part of the Cloud Foundation Toolkit and follows Google Cloud best practices for infrastructure management.
The repository implements a modular architecture with three distinct entry points, each serving different service account management workflows. The root module uses Terraform's for_each meta-argument to manage multiple service accounts and their IAM bindings.
For detailed information on specific module components, see Module Structure. For version compatibility requirements, see Version Requirements.
Service Account Identity Model in GCP
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 [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. The identity model separates human credentials from machine credentials. This separation allows rotation, auditing, and least privilege enforcement without impacting individual users.
The email address format is [email protected]. The key pair supports JSON web token signing and authentication. IAM role bindings can be applied at project, organization, or billing scope.
Creating a Service Account with gcloud CLI
Creating a service account with gcloud provides the baseline identity before Terraform management.
Using gcloud CLI
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"
gcloud iam service-accounts list
The command sets the project context, creates the service account with display name and description, and verifies creation. The display name is human readable, the description documents purpose.
Assigning Roles to Service Accounts
Grant the service account the permissions it needs. Roles can be granted at project level using gcloud projects add-iam-policy-binding.
Assigning roles
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:terraform@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.admin"
For a general-purpose Terraform service account, you might use the Editor role during initial setup and tighten it later:
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:terraform@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/editor"
Broad access for initial setup is not recommended for production. The principle of least privilege requires tightening roles after initial bootstrap.
Key considerations for permissions:
- Permissions: Ensure your Terraform code has the necessary permissions to create service accounts and assign roles.
- Resource Hierarchy: Adjust the resource type based on the desired level of role assignment, project, organization, etc.
- Service Account Deletion: Be aware of potential propagation delays when deleting and recreating service accounts with the same name.
- Alternative Approaches: Explore using loops with count or modules for managing roles across multiple service accounts.
Terraform Resource Model for Service Accounts and Roles
This guide explains how to create a Google Cloud Platform service account and assign it roles using Terraform. The example code includes explanations and important considerations for managing service accounts and their permissions effectively.
To create a GCP service account with roles using Terraform, generally follow these steps:
- Define the service account
- Define the roles
- Assign roles using googleprojectiam_member
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",
]
}
You can either list roles directly or use variables for better organization.
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.
By combining the googleserviceaccount and googleprojectiammember resources with Terraform's built-in functionalities like foreach, you can efficiently manage service accounts and their roles in your GCP projects. This approach enables infrastructure as code, ensuring that service accounts have the correct permissions for applications and workflows. Remember to follow security best practices, such as the principle of least privilege, and consult the Terraform Google provider documentation for the latest features and updates. By automating this process, you can minimize errors, improve consistency, and streamline cloud infrastructure management.
Iteration through roles uses for_each to iterate through the list of roles and assign each one to the service account.
for_each = toset(var.roles)
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.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)
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.
Authentication Methods
Method | Description | Credential Storage
Service Account Key File | JSON key with private material | File or environment variable
Environment Variable | GOOGLE_CREDENTIALS or GOOGLE_APPLICATION_CREDENTIALS | Process environment
Service Account Impersonation | Short-lived token via gcloud auth | Application Default Credentials
Service Account Impersonation and Application Default Credentials
Authenticate using service account impersonation. You can use service account impersonation to set up a local ADC file. Terraform uses those credentials automatically.
Make sure you must have the Service Account Token Creator roles/iam.serviceAccountTokenCreator IAM role on the service account you are impersonating. For more information, see Required roles.
Use service account impersonation to create a local ADC file by running the following command:
gcloud auth application-default login --impersonate-service-account SERVICE_ACCT_EMAIL
If you want to allow users to use a shared primary authentication source and a variable service account per environment, set the impersonateserviceaccount field in your Terraform configuration file:
provider "google" {
impersonate_service_account = "SERVICE_ACCT_EMAIL"
}
After you sign in, your credentials are stored in the local credential file used by ADC.
Authenticate when running Terraform on Google Cloud
When running Terraform on a Google Cloud cloud-based development environment such as Cloud Shell, the tool uses the credentials you provided when you signed in for authentication.
When using Terraform with Google Cloud services such as Compute Engine, App Engine, and Cloud Run functions, you can attach a user-managed service account to resources. Generally, attaching a service account is supported when that service's resources can run or include application code.
Module Structure and Multi-Account Management
The terraform-google-service-accounts module automates provisioning of service accounts, assignment of IAM roles at multiple scopes project, organization, billing, optional key generation, and includes specialized submodules for simplified single-account creation and secure key distribution.
The root module uses Terraform's for_each meta-argument to manage multiple service accounts and their IAM bindings. This enables declarative management of a fleet of service accounts from a single input map.
The repository implements a modular architecture with three distinct entry points, each serving different service account management workflows.
Module Entry Points
Entry Point | Workflow
Root Module | Multiple service accounts with for_each
Single Account Submodule | Simplified single-account creation
Key Distribution Submodule | Secure key distribution
The module is maintained as part of the Cloud Foundation Toolkit and follows Google Cloud best practices for infrastructure management.
Security Considerations and Operational Best Practices
Permissions: Ensure your Terraform code has the necessary permissions to create service accounts and assign roles.
Resource Hierarchy: Adjust the resource type based on the desired level of role assignment, project, organization, etc.
Service Account Deletion: Be aware of potential propagation delays when deleting and recreating service accounts with the same name.
Alternative Approaches: Explore using loops with count or modules for managing roles across multiple service accounts.
Service account keys are long-lived credentials and must be handled securely. chmod 600 terraform-key.json is a minimum protection. Keys should be rotated regularly and stored in secret managers.
Principle of least privilege should guide role selection. Initial broad roles like roles/editor should be replaced with granular roles such as roles/cloudsql.admin, roles/storage.objectViewer, roles/pubsub.publisher.
Impersonation avoids long-lived keys. Service account impersonation requires roles/iam.serviceAccountTokenCreator on the impersonated service account.
Conclusion
Terraform Google service account management spans identity creation, IAM binding, provider authentication, and module abstraction. A GCP service account provides a project-owned identity with email, key pair, and IAM role bindings for automated workloads. Creation via gcloud iam service-accounts create establishes the baseline identity, while Terraform resources googleserviceaccount and googleprojectiammember enable infrastructure as code with foreach iteration over role sets.
Authentication can be performed with long-lived service account key files referenced via credentials = file or GOOGLECREDENTIALS environment variable, or with short-lived tokens via service account impersonation using impersonateservice_account in provider configuration and gcloud auth application-default login --impersonate-service-account. Cloud Shell and attached user-managed service accounts provide additional native authentication paths.
The terraform-google-service-accounts module from Cloud Foundation Toolkit codifies these patterns with a modular architecture supporting multiple entry points, for_each-based multi-account management, role assignments at project, organization, and billing scopes, and optional key generation. Operational best practices require least privilege role selection, secure key handling, awareness of propagation delays on deletion and recreation, and appropriate resource hierarchy for IAM binding. Combining declarative module usage with correct provider authentication yields consistent, auditable, and secure Terraform deployments against Google Cloud.