Identity and Access Management: Service Accounts & Bindings
Scenario
In Google Cloud, applications and resources authenticate using Service Accounts rather than human user credentials. You need to create a service account designated for an application that needs to read from Google Cloud Storage, and assign it the appropriate storage object viewer role at the project level.
Your Objectives
- Create a google_service_account for your data-reader application.
- Assign the roles/storage.objectViewer role to the service account using a google_project_iam_member resource.
- Output the email address of the generated service account.
Additional Context
IAM Member vs Binding vs Policy:
- google_project_iam_member adds a single role to a single user non-destructively. (Best for automation).
- google_project_iam_binding manages all members for a specific role. Anyone not in your Terraform code will be removed from that role.
- google_project_iam_policy assumes complete authority over all IAM roles at the project. It removes anything you didn't define.
variables.tf
variable "project_id" { type = string }main.tf
provider "google" {
project = var.project_id
}
# Create the Service Account
resource "google_service_account" "app_sa" {
account_id = "app-data-reader"
display_name = "Application Data Reader SA"
description = "Service account for the app to read GCS datasets"
}
# Grant the Service Account read access to Cloud Storage across the project
# Use _member, NOT _binding or _policy to avoid overwriting existing permissions
resource "google_project_iam_member" "sa_storage_viewer" {
project = var.project_id
role = "roles/storage.objectViewer"
# GCP expects the member to be prefixed with the account type
member = "serviceAccount:${google_service_account.app_sa.email}"
}outputs.tf
output "service_account_email" {
value = google_service_account.app_sa.email
}Workflow Commands
terraform init
terraform apply -var="project_id=my-gcp-project-123"
# Verify the IAM policy binding on the project
gcloud projects get-iam-policy my-gcp-project-123 \
--flatten="bindings[].members" \
--format='table(bindings.role)' \
--filter="bindings.members:$(terraform output -raw service_account_email)"
terraform destroy -var="project_id=my-gcp-project-123"
✓ Expected Output After Apply
Apply complete! Resources: 2 added, 0 changed, 0 destroyed. Outputs: service_account_email = "[email protected]"

