The most surprising thing about authenticating GitHub Actions to GCP is that you don’t actually create or manage any long-lived GCP credentials that leak into your GitHub repository.
Let’s see this in action. Imagine you have a GitHub Action that needs to deploy a web application to a Google Cloud Run service. Your main.workflow (or .github/workflows/deploy.yml in GitHub’s standard) might look something like this:
name: Deploy to Cloud Run
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v1
with:
workload_identity_provider: "projects/1234567890/locations/global/workloadIdentityPools/my-pool/providers/my-github-provider"
service_account: "github-actions-deployer@my-gcp-project.iam.gserviceaccount.com"
- name: Deploy to Cloud Run
run: gcloud run deploy my-app --image gcr.io/my-gcp-project/my-app:latest --region us-central1 --platform managed --allow-unauthenticated
In this workflow, the google-github-actions/auth@v1 action is the magic. It takes two key pieces of information:
workload_identity_provider: This is a pointer to a specific identity provider within your Google Cloud Workload Identity Pool.service_account: This is the email address of a GCP Service Account that your GitHub Actions will impersonate.
When this action runs, it doesn’t fetch a JSON key file. Instead, it uses the GitHub Actions OIDC token (which is signed by GitHub and verifiable by GCP) to request short-lived credentials from GCP’s Workload Identity Federation. GCP verifies the OIDC token’s origin and claims, and if valid, issues temporary credentials for the specified service account. These credentials are then automatically configured for gcloud and other GCP client libraries within the action’s environment.
This system solves a critical security problem: credential sprawl. Before Workload Identity Federation, the common pattern was to create a GCP Service Account, generate a JSON key for it, and then store that key as a GitHub Secret. This meant a long-lived credential was sitting in your repository’s secrets, a prime target for compromise. If that secret was leaked, an attacker would have direct, persistent access to GCP as that service account.
With Workload Identity Federation, the connection is established through OIDC tokens. GitHub acts as the identity provider. When your action runs, GitHub generates a unique, short-lived OIDC token for that specific workflow run. This token contains claims about the workflow (e.g., the repository, branch, actor). GCP’s Workload Identity Pool is configured to trust GitHub as an OIDC provider and to map specific GitHub claims to a GCP Service Account. The google-github-actions/auth action orchestrates this exchange. It obtains the OIDC token, sends it to GCP’s Workload Identity Federation endpoint, and receives temporary credentials in return. These credentials are then used by subsequent steps in your action to interact with GCP.
The core components you configure on the GCP side are:
- Workload Identity Pool: A container for identity providers.
- Workload Identity Provider: Configured to trust GitHub’s OIDC issuer URL (
https://token.actions.githubusercontent.com) and to map specific attributes from the GitHub OIDC token (like repository name or branch) to GCP attributes. This is where you define the trust relationship. - Service Account: The GCP identity your GitHub Action will impersonate.
- IAM Policy Binding: This is crucial. You grant the Workload Identity Pool Provider permission to impersonate the target Service Account. This is done by adding a binding to the Service Account’s IAM policy, granting the
roles/iam.workloadIdentityUserrole to the identity of the Workload Identity Pool Provider. The principal for this role looks likeprincipalSet://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/attribute.repository/<REPO_NAME>(or similar, depending on how you configure attribute mapping).
A common point of confusion is how the mapping works. You don’t just point a provider at GitHub; you tell GCP which GitHub Actions runs are allowed to impersonate which service account. This is done by defining attribute conditions on the IAM policy binding. For example, you might configure your Workload Identity Provider to extract the repository claim from the GitHub OIDC token and make it available as a GCP attribute. Then, when you grant the roles/iam.workloadIdentityUser role to the provider, you can add a condition like attribute.repository == "my-org/my-repo" to restrict which repositories can use that provider to impersonate the service account.
The next challenge you’ll likely encounter is managing fine-grained permissions for the service account itself, ensuring it only has the minimum necessary roles to perform its tasks.