I was setting up GitHub Actions to deploy to GCP and needed to use workload identity instead of service account keys. Here’s how to manage the providers.

TLDR Link to heading

Workload identity lets GitHub Actions authenticate to GCP without storing service account keys. It’s more secure because:

  • No static credentials to rotate or leak
  • Fine-grained control over which repos can access what
  • Built-in audit trail of who authenticated when

The main gotcha: you need id-token: write permission in your workflow or auth fails silently.

List providers in a pool:

gcloud iam workload-identity-pools providers list \
    --workload-identity-pool=github-actions \
    --location=global \
    --project=my-project

Describe one:

gcloud iam workload-identity-pools providers describe github \
    --workload-identity-pool=github-actions \
    --location=global \
    --project=my-project

Delete an old one:

gcloud iam workload-identity-pools providers delete old-provider \
    --workload-identity-pool=github-actions \
    --location=global \
    --project=my-project

In the GitHub workflow, make sure you have:

permissions:
  contents: read
  id-token: write  # This is the important one

Without id-token: write, the authentication fails silently.

Why workload identity? Link to heading

Service account keys are a security risk. If they leak (in logs, git history, etc.), someone can impersonate your service account until you notice and rotate the key. I’ve seen keys accidentally committed to repos multiple times.

Workload identity uses OIDC tokens that are short-lived (minutes, not years) and scoped to the specific workflow run. Even if someone intercepts the token, it’s useless by the time they try to use it.

Plus, you can configure exactly which repos and branches can authenticate. No more blanket access for any workflow that has the key.

Debugging authentication failures Link to heading

If auth isn’t working, check these in order:

  1. Missing id-token permission - This is the most common issue. The workflow needs id-token: write at the job or workflow level.

  2. Wrong attribute mapping - The workload identity provider needs to trust tokens from your repo. Check the attribute conditions:

    gcloud iam workload-identity-pools providers describe github \
        --workload-identity-pool=github-actions \
        --location=global \
        --project=my-project \
        --format='value(attributeCondition)'
    
  3. Service account permissions - The service account needs roles/iam.workloadIdentityUser binding for the right principal:

    gcloud iam service-accounts add-iam-policy-binding [email protected] \
        --role=roles/iam.workloadIdentityUser \
        --member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-actions/attribute.repository/my-org/my-repo"
    
  4. Check the GitHub token - Use google-github-actions/auth@v2 with token_format: access_token and add a debug step to print claims (careful not to print the token itself).

The error messages are often vague (“authentication failed”), so methodically checking each layer is the only way.

Further reading Link to heading