How to Safely Link Terraform Cloud and Google Cloud Platform via Workload Identity Federation

How to Safely Link Terraform Cloud and Google Cloud Platform via Workload Identity Federation

Terraform Cloud is a great service for managing Terraform configurations and applying them to provision infrastructure across different cloud providers, including Google Cloud Platform (GCP). However, securely authenticating Terraform Cloud to GCP can be a challenge. Workload Identity Federation is a new feature in GCP that allows you to safely authenticate access to GCP resources without using long-lived credentials like service account keys. This post will walk through how to set up Workload Identity Federation between Terraform Cloud and GCP.

If you prefer French, check PoC video here

Prerequisites:

  • A GCP project

  • A Terraform Cloud account and workspace

Step 1: Enable Required GCP APIs First, you need to enable the required APIs in your GCP project:

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

Step 2: Create a Google Cloud Workload Identity Pool: It's a collection of workloads that share the same identity and access policy. Create one with:

gcloud iam workload-identity-pools create tfc-wif-pool \
  --project=<PROJECT_ID> \
  --location=global

Step 3: Create a Google Cloud Workload Identity Pool Provider: This links your external identity provider (in this case Terraform Cloud) to the workload identity pool:

gcloud iam workload-identity-pools providers create-oidc tfc-wif-provider \
  --project=<PROJECT_ID> \
  --location=global \
  --workload-identity-pool=tfc-wif-pool \
  --issuer-uri=https://app.terraform.io \
  --attribute-mapping="google.subject=assertion.terraform_workspace_id"

Step 4: Create a Google Service Account for Terraform: This represents the identity that Terraform will use:

gcloud iam service-accounts create tfc-wif-sa \
  --project=<PROJECT_ID>

Step 5: Allow the Service Account to user the Workload Identity:

gcloud projects add-iam-policy-binding <PROJECT_ID> \
    --member serviceAccount:tfc-wif-sa@<PROJECT_ID>.iam.gserviceaccount.com \
    --role roles/iam.workloadIdentityUser

Step 6: Add Permissions to the Service Account and any required permissions to the service account, such as the ability to create and manage compute Engine resources:

gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member="serviceAccount:tfc-wif-sa@<PROJECT_ID>.iam.gserviceaccount.com" \
  --role="roles/compute.admin"

Step 7: Configure Terraform Cloud In your Terraform Cloud workspace:

  1. Go to "Variables" and create a new environment : change PROJECT_NUMBER and PROJECT_ID

     TFC_GCP_PROJECT_NUMBER = <PROJECT_NUMBER> 
     TFC_GCP_PROVIDER_AUTH = true    
     TFC_GCP_RUN_SERVICE_ACCOUNT_EMAIL = tfc-wif-sa@<PROJECT_ID>.iam.gserviceaccount.com
     TFC_GCP_WORKLOAD_POOL_ID = tfc-wif-pool
     TFC_GCP_WORKLOAD_PROVIDER_ID = tfc-wif-provider
    

  2. UpdateWorkload Identity Federation to add service tfc-wif-sa@<PROJECT_ID>.iam.gserviceaccount.com

    Click on tfc-wif-pool Display Name

  3. And Click Grant Access

  4. Add your SA email

    Add your Terraform cloud Workspace ID like this:

    Copy your **ws-**xSSKSSSSSS

  5. Update subject with the workspace ID subject and Click on "SAVE" in the popup page, click on DISMISS

  6. Your provider CONNECTED SERVICE ACCOUNTS should look like this

  7. create a terraform file main.tf, add the google provider block and resource to create Compute Engine Instance:

terraform {
  cloud {
    organization = "change_me" # change this

    workspaces {
      name = "tfc-gcp-wif"
    }
  }
}

provider "google" {
  project = var.gcp_project_id
  region  = var.gcp_region
  zone    = var.gcp_zone
}

variable "gcp_project_id" {}

variable "gcp_region" {
  default = "us-east4"
}

variable "gcp_zone" {
  default = "us-east4-c"
}

resource "google_compute_instance" "test-instance" {
  name         = "test-instance"
  machine_type = "n1-standard-1"
  zone         = var.gcp_zone

  boot_disk {
    initialize_params {
      image = "centos-cloud/centos-7"
      size = 20
    }
  }

  network_interface {
    subnetwork = "default"
  }
}

Run terraform init, terraform plan and terraform apply --auto-approve

Congratulations, you did it !

That's it! Terraform Cloud can now securely provision resources in your GCP project using Workload Identity Federation without needing to manage long-lived service account keys. The service account permissions can be scoped as needed, and the external identity is validated by GCP for each run.

Don't forget to destroy ressources !