Multi-Project Security: Cross-Project IAM and Storage
Scenario
An application running in your "App Project" needs to securely read analytics data stored in a Cloud Storage bucket located in your completely separate "Data Project". You will provision a Service Account in Project A, create a Bucket in Project B, and use Terraform's ability to manage resources across multiple projects via provider aliases to grant the precise IAM role needed.
- Define two distinct Google providers using the alias meta-argument.
- Create a google_service_account in the "App" project.
- Create a google_storage_bucket in the "Data" project.
- Create a google_storage_bucket_iam_member binding that lives in the "Data" project, granting `roles/storage.objectViewer` to the Service Account that lives in the "App" project.
Additional Context
Provider Aliases: When executing Terraform, you usually declare one `provider "google"` block pointing to your primary project. To manage resources in a secondary project simultaneously, you define a second `provider "google"` block mapped to a new alias (`alias = "data_project"`). When creating resources for the second project, you must explicitly inject `provider = google.data_project`.
IAM Federation: In GCP, IAM Principals (like Service Accounts) are globally routable via their exact email address string. A bucket in Project B can seamlessly grant permissions to `[email protected]`.
variables.tf
variable "app_project_id" { type = string }
variable "data_project_id" { type = string }main.tf
# The Default Provider (Project A)
provider "google" {
project = var.app_project_id
region = "us-central1"
}
# The Alias Provider (Project B)
provider "google" {
alias = "data"
project = var.data_project_id
region = "us-central1"
}
# 1. Identity lives in the App Project (Uses Default Provider)
resource "google_service_account" "app_sa" {
account_id = "app-workload-runner"
display_name = "Application Service Account"
}
# 2. Storage Bucket lives in the Data Project (Uses Alias Provider)
resource "random_id" "bkt" { byte_length = 4 }
resource "google_storage_bucket" "analytics_bucket" {
# Explicitly tell Terraform to use the data project provider credentials
provider = google.data
name = "corporate-analytics-${random_id.bkt.hex}"
location = "US"
}
# 3. Apply the IAM rule IN the Data Project, granting access TO the App Project SA
resource "google_storage_bucket_iam_member" "cross_project_read" {
# The IAM resource MUST exist in the same provider as the bucket
provider = google.data
bucket = google_storage_bucket.analytics_bucket.name
role = "roles/storage.objectViewer"
# Interpolate the email string dynamically
member = "serviceAccount:${google_service_account.app_sa.email}"
}Workflow Commands
terraform init
# Make sure the user executing Terraform has sufficient IAM privileges in BOTH projects
terraform apply \
-var="app_project_id=app-dev-111" \
-var="data_project_id=data-bureau-222"
terraform destroy \
-var="app_project_id=app-dev-111" \
-var="data_project_id=data-bureau-222"
