GitHub Actions + GCP Authentication without Secrets

Workload Identity Federation lets GitHub Actions authenticate with Google Cloud without storing service account keys. Instead, GitHub's OpenID Connect (OIDC) token is exchanged for a short-lived GCP access token. This way, there is no secrets to rotate, as tokens are short-lived and generated on demand

The following placeholders are used in the commands below:

PlaceholderDescription
PROJECT_IDGCP project ID (e.g. playground-12345)
PROJECT_NUMBERGCP project number (e.g. 123456789012) obtained from step 1
GITHUB_ORGGitHub organization or user name
GITHUB_REPOGitHub repository name
  1. Obtain the project number:

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
  2. Create a Workload Identity Pool

    gcloud iam workload-identity-pools create "github" \
      --project="PROJECT_ID" \
      --location="global" \
      --display-name="GitHub Actions Pool"
  3. Create a Workload Identity Provider

    gcloud iam workload-identity-pools providers create-oidc "my-repo" \
      --project="PROJECT_ID" \
      --location="global" \
      --workload-identity-pool="github" \
      --display-name="GitHub Actions Provider" \
      --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner" \
      --attribute-condition="assertion.repository_owner == 'GITHUB_ORG'" \
      --issuer-uri="https://token.actions.githubusercontent.com"

    The --attribute-condition restricts access to the specified GitHub org/user. With these attribute mappings, you can use them as a principal identifier when granting access to GCP resources.

    For example, to only allow a specific repository (GITHUB_ORG/GITHUB_REPO) to access a GCP resource, you can grant access to the principal identifier:

    principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github/attribute.repository/GITHUB_ORG/GITHUB_REPO
    
  4. Create a Service Account

    gcloud iam service-accounts create "SERVICE_ACCOUNT_NAME" \
      --project="PROJECT_ID" \
      --display-name="GitHub Actions - my-repo"
  5. Grant Permissions to the Service Account

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com" \
      --role="roles/bigquery.dataEditor" \
      --condition=None
  6. Allow GitHub to Impersonate the Service Account

    gcloud iam service-accounts add-iam-policy-binding \
      "SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com" \
      --project="PROJECT_ID" \
      --role="roles/iam.workloadIdentityUser" \
      --member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github/attribute.repository/GITHUB_ORG/GITHUB_REPO"
  7. Enable the IAM Credentials API

    gcloud services enable iamcredentials.googleapis.com --project=PROJECT_ID
  8. Use in GitHub Actions

    jobs:
      my-job:
        runs-on: ubuntu-latest
        permissions:
          contents: read
          id-token: write
        steps:
          - uses: actions/checkout@v4
          - uses: google-github-actions/auth@v2
            with:
              workload_identity_provider: projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github/providers/my-repo
              service_account: SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com
          # Now authenticated with GCP

    The id-token: write permission is required for the OIDC token exchange.