• DevOps Lab Notes
  • Posts
  • Level Up Your Terraform Cloud Security: GCS Buckets with Workload Identity Federation

Level Up Your Terraform Cloud Security: GCS Buckets with Workload Identity Federation

Ditch API keys for good — learn how to securely provision GCS buckets from Terraform Cloud using Workload Identity Federation, the modern way to authenticate to GCP.

Tired of managing cumbersome API keys for your Terraform Cloud deployments to GCP? There’s a better, more secure way.

In my previous lab post, I showed how to provision a Google Cloud Storage (GCS) bucket using Terraform Cloud (TFC) — but with long-lived service account keys for authentication.

That method works… but it comes with real security baggage:

  • Static credentials that must be rotated manually

  • Higher risk if keys are leaked

  • Clumsy management overhead in CI/CD pipelines

This post is all about solving that problem — by ditching API keys and upgrading to Workload Identity Federation (WIF).

Why Workload Identity Federation? 🔐

Workload Identity Federation allows external identities (like Terraform Cloud, GitHub Actions, etc.) to authenticate to GCP without needing service account keys. Instead of uploading secrets, your CI/CD platform presents an OIDC identity that GCP trusts — and issues short-lived tokens in return.

Key Benefits of WIF Over API Keys:

  • ✅ Better security: No long-lived secrets, short-lived tokens, automatic rotation

  • ✅ Reduced credential sprawl: No need to manage and distribute service account keys

  • ✅ Granular access control: Attribute-based identity mapping lets you apply least privilege per workspace

  • ✅ Improved auditability: Authentication is tied to identity pools and issuers

Step-by-Step: Provision GCS Bucket with WIF

Let’s walk through exactly how to create a GCS bucket from Terraform Cloud using Workload Identity Federation.

🔧 Step 1: Enable Required GCP APIs

gcloud services enable \
  iam.googleapis.com \
  iamcredentials.googleapis.com \
  cloudresourcemanager.googleapis.com

☁️ Step 2: Create a Workload Identity Pool

gcloud iam workload-identity-pools create tfc-pool \
  --location="global" \
  --display-name="Terraform Cloud Pool"

This creates a container for trusted external identities — like Terraform Cloud workspaces.

🪪 Step 3: Add an OIDC Provider for Terraform Cloud

gcloud iam workload-identity-pools providers create-oidc tfc-provider \
  --location="global" \
  --workload-identity-pool="tfc-pool" \
  --display-name="Terraform Cloud Provider" \
  --issuer-uri="https://app.terraform.io" \
  --attribute-mapping="google.subject=assertion.sub" \
  --attribute-condition="assertion.sub.startsWith("organization:<ORG-NAME>:project:<PROJECT_NAME>:workspace:<WORKSPACE_NAME>")"

👤 Step 4: Create a Service Account

gcloud iam service-accounts create tfc-deployer \
  --display-name="Terraform Cloud Deployer"

This account will be impersonated by Terraform Cloud via WIF.

👥 Step 5: Allow Pool to Impersonate Service Account


gcloud iam service-accounts add-iam-policy-binding tfc-deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="principal://iam.googleapis.com/projects/$PROJECT_NUM/locations/global/workloadIdentityPools/$POOL_ID/subject/organization:$ORG:project:$TFC_PROJECT:workspace:$WORKSPACE:run_phase:plan"
gcloud iam service-accounts add-iam-policy-binding tfc-deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com \
  --role=roles/iam.serviceAccountTokenCreator \
  --member="principal://iam.googleapis.com/projects/$PROJECT_NUM/locations/global/workloadIdentityPools/$POOL_ID/subject/organization:$ORG:project:$TFC_PROJECT:workspace:$WORKSPACE:run_phase:apply"

Replace the following and allow some time for permissions to sync.

  • YOUR_PROJECT_ID

  • PROJECT_NUM

  • POOL_ID

  • ORG

  • TFC_PROJECT

  • WORKSPACE

🗂️ Step 6: Grant Storage Admin role to Service Account

gcloud projects add-iam-iam-policy-binding PROJECT_ID --member="serviceAccount:tfc-deployer@PROJECT_ID.iam.gserviceaccount.com" --role="roles/storage.admin"

This lets Terraform Cloud create buckets. For production use, consider more granular roles like storage.objectCreator.

⚙️ Step 7: Configure Terraform Cloud Workspace Variables

In your Terraform Cloud workspace, add the following environment variables:

Name

Value

Sensitive

project_id

Your GCP project ID

No

TFC_GCP_PROVIDER_AUTH

true

No

TFC_GCP_RUN_SERVICE_ACCOUNT_EMAIL

[email protected]

No

region

us-central1

No

TFC_GCP_WORKLOAD_PROVIDER_ID

projects/YOUR_PROJECT_NUMBER/locations/global/workloadIdentityPools/tfc-pool/providers/tfc-provider

No

Marking sensitive variables is optional here as none of these contain secrets — but it’s good hygiene.

📦 Step 8: Terraform HCL for GCS Bucket

Here’s a minimal main.tf to test the setup:

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "6.50.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

resource "google_storage_bucket" "example" {
  name     = "my-wif-secured-bucket-${random_id.bucket_suffix.hex}"
  location = var.region
  uniform_bucket_level_access = true
  labels = {
    environment = "test"
  }
}

resource "random_id" "bucket_suffix" {
  byte_length = 4
}

variable "project_id" {
  description = "The GCP project ID where resources will be created"
  type        = string
}

variable "region" {
  description = "The GCP region to deploy resources into"
  type        = string
}

✅ Testing & Verification

  1. Push your Terraform code to GitHub (or your VCS).

  2. Trigger a plan or apply in Terraform Cloud.

  3. Confirm:

    • No API key or static credentials required

    • Authentication succeeds in run logs

    • GCS bucket appears in your GCP console

🧯 Troubleshooting & Best Practices

  • Double-check IAM roles and identity pool bindings

  • Ensure your terraform_workspace_id in attribute mapping matches your TFC workspace

  • Always prefer least privilege — avoid giving storage.admin if your use case only needs object creation

  • Use separate pools/providers for different environments (dev, staging, prod)

🔚 Conclusion: Make WIF Your Default

Workload Identity Federation represents the next step in secure, scalable Terraform-GCP workflows.

  • No more API key sprawl

  • Fine-grained access controls

  • Seamless integration with Terraform Cloud

If you're still using service account keys, now's the time to switch. WIF is what modern CI/CD pipelines need — especially when managing cloud infrastructure at scale.

📬 Want More Like This?

👉 Subscribe to DevOps Lab Notes on Beehiiv to stay in the loop.

#DevOps #TerraformCloud #GoogleCloud #WorkloadIdentityFederation #IaC #CloudSecurity #Terraform #GCP #CI/CD #SecurityBestPractices