Workload Identity is the GCP-native way to grant Google Cloud services access to other Google Cloud services without managing service account keys.
Here’s a GitHub Actions workflow deploying a simple Go application to Google Cloud Run, authenticated using Workload Identity.
name: Deploy to Cloud Run with Workload Identity
on:
push:
branches:
- main
env:
GCP_PROJECT_ID: your-gcp-project-id
GCP_REGION: us-central1
GCP_SERVICE_ACCOUNT_NAME: github-actions-sa
GCP_WORKLOAD_IDENTITY_POOL_ID: github-actions-pool
GCP_WORKLOAD_IDENTITY_PROVIDER_ID: github-actions-provider
SERVICE_NAME: my-github-actions-app
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Build Go app
run: go build -o app main.go
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v1
with:
workload_identity_provider: projects/${{ env.GCP_PROJECT_ID }}/locations/global/workloadIdentityPools/${{ env.GCP_WORKLOAD_IDENTITY_POOL_ID }}/providers/${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER_ID }}
service_account: ${{ env.GCP_SERVICE_ACCOUNT_NAME }}@${{ env.GCP_PROJECT_ID }}.iam.gserviceaccount.com
- name: Deploy to Cloud Run
uses: google-github-actions/deploy-cloudrun@v1
with:
service: ${{ env.SERVICE_NAME }}
region: ${{ env.GCP_REGION }}
project: ${{ env.GCP_PROJECT_ID }}
image: gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}
tag: latest # Or use github.sha for specific versions
This workflow does the following:
- Checks out your code.
- Sets up Go to build your application.
- Builds the Go binary.
- Authenticates to Google Cloud using the
google-github-actions/authaction. This is where Workload Identity shines. Instead of downloading a service account key, it uses a pre-configured Workload Identity Pool and Provider to exchange your GitHub Actions identity for a short-lived GCP credential. - Deploys to Cloud Run using the
google-github-actions/deploy-cloudrunaction. This action automatically builds a container image (if you don’t provide one) and deploys it.
To make this work, you need to set up Workload Identity in GCP first. This involves:
- Creating a Google Cloud Service Account: This SA will be granted permissions for your Cloud Run deployment.
- Creating a Workload Identity Pool: This pool represents external identities that can impersonate GCP service accounts.
- Creating a Workload Identity Provider: This provider within the pool is configured to trust GitHub Actions. You’ll set an attribute mapping to ensure GitHub Actions can identify itself correctly.
- Granting the Service Account to the Provider: This links the GCP service account to the Workload Identity provider, allowing it to be impersonated.
- Granting necessary IAM roles to the Service Account: For example,
roles/run.adminandroles/iam.serviceAccountUser(on the Cloud Run service account, if different). - Configuring GitHub Actions: Using the
google-github-actions/authaction with the correctworkload_identity_providerandservice_accountparameters.
The beauty of Workload Identity is that it eliminates the need to manage and rotate long-lived service account keys, which is a significant security improvement. The GitHub Actions runner obtains temporary credentials based on its identity, which is verified by the Workload Identity Provider.
The core of Workload Identity’s magic lies in the OIDC (OpenID Connect) token exchange. When GitHub Actions runs, it generates an OIDC token that contains claims about the repository, branch, and environment. The Workload Identity Provider in GCP is configured to trust tokens from token.actions.githubusercontent.com. When the google-github-actions/auth action is invoked, it sends this OIDC token to GCP. GCP’s Workload Identity service verifies the token’s signature and checks the claims against the provider’s configuration. If they match, GCP issues short-lived credentials for the specified service account. This process is entirely keyless from the perspective of your CI/CD pipeline.
A common point of confusion is the difference between the Workload Identity Pool and Provider. The Pool is a container for providers. The Provider is the actual configuration that trusts a specific external identity source (like GitHub Actions) and maps its attributes to GCP attributes. You can have multiple providers within a single pool, for example, one for GitHub Actions and another for GitLab CI.
The google-github-actions/auth action handles the complexity of this OIDC exchange for you. You simply provide the full resource name of your Workload Identity Provider and the email of the GCP Service Account you want to impersonate. The action automatically retrieves the OIDC token from the GitHub Actions environment and makes the exchange.
You’ll likely encounter a permissions error if the GitHub Actions workflow tries to access a resource that the github-actions-sa service account doesn’t have explicit IAM permissions for.
name: Deploy to Cloud Run with Workload Identity
on:
push:
branches:
- main
env:
GCP_PROJECT_ID: your-gcp-project-id
GCP_REGION: us-central1
GCP_SERVICE_ACCOUNT_NAME: github-actions-sa
GCP_WORKLOAD_IDENTITY_POOL_ID: github-actions-pool
GCP_WORKLOAD_IDENTITY_PROVIDER_ID: github-actions-provider
SERVICE_NAME: my-github-actions-app
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Build Go app
run: go build -o app main.go
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v1
with:
workload_identity_provider: projects/${{ env.GCP_PROJECT_ID }}/locations/global/workloadIdentityPools/${{ env.GCP_WORKLOAD_IDENTITY_POOL_ID }}/providers/${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER_ID }}
service_account: ${{ env.GCP_SERVICE_ACCOUNT_NAME }}@${{ env.GCP_PROJECT_ID }}.iam.gserviceaccount.com
- name: Deploy to Cloud Run
uses: google-github-actions/deploy-cloudrun@v1
with:
service: ${{ env.SERVICE_NAME }}
region: ${{ env.GCP_REGION }}
project: ${{ env.GCP_PROJECT_ID }}
image: gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}
tag: latest # Or use github.sha for specific versions
This workflow demonstrates how to deploy an application to Google Cloud Run using GitHub Actions and Workload Identity. The google-github-actions/auth action handles the authentication by exchanging the GitHub Actions OIDC token for temporary Google Cloud credentials. This eliminates the need for managing service account keys, enhancing security and simplifying your CI/CD pipeline. The google-github-actions/deploy-cloudrun action then uses these credentials to deploy your application.
The key to understanding Workload Identity is realizing it’s a trust relationship. GCP trusts a specific external identity provider (like GitHub Actions) to issue verifiable tokens. Your Workload Identity Pool and Provider are configured to accept these tokens and map them to a GCP Service Account. When your GitHub Actions workflow runs, it presents its OIDC token, which GCP verifies. If the token is valid and the claims match the provider’s configuration, GCP grants temporary credentials for the associated Service Account. This is a fundamentally different and more secure model than downloading and storing static keys.
The workload_identity_provider field in the google-github-actions/auth action requires the full resource path to your provider, which looks like projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID. You can find your project number in the GCP console or by running gcloud projects describe YOUR_PROJECT_ID --format='value(projectNumber)'. The POOL_ID and PROVIDER_ID are what you defined when setting up Workload Identity.
Once authenticated, subsequent actions like deploy-cloudrun will automatically use the obtained credentials to interact with GCP services. This seamless integration means you don’t need to explicitly pass credentials to every Google Cloud action. The google-github-actions/auth action sets up the environment for other actions to use.
The deploy-cloudrun action, in this example, will build a Docker image if one isn’t provided and push it to Google Container Registry (GCR) or Artifact Registry before deploying it to Cloud Run. Ensure your github-actions-sa has permissions to push to GCR/Artifact Registry as well, typically roles/storage.admin for GCR or roles/artifactregistry.writer for Artifact Registry.
A crucial detail often overlooked is the attribute mapping within the Workload Identity Provider configuration. When you set up the provider, you define how attributes from the external token (e.g., repository name, branch name) map to GCP attributes. For GitHub Actions, you’ll typically map github.repository to a google.subject or a custom attribute, and github.ref to another. This mapping is what GCP uses to verify the identity. Without correct attribute mapping, the OIDC token exchange will fail.
You’ll likely hit a "permission denied" error when the deploy-cloudrun action tries to create a Cloud Run service if the github-actions-sa doesn’t have the roles/run.admin IAM role.