Implementing Secure Authentication for GitHub Actions via Google Cloud Workload Identity Federation

The integration of Continuous Integration and Continuous Deployment (CI/CD) pipelines with cloud infrastructure has historically relied on the exchange of static credentials. For developers utilizing GitHub Actions to deploy resources into Google Cloud Platform (GCP), the traditional method involved the generation of a service account JSON key. This key would then be stored as a GitHub Secret and injected into the workflow at runtime. While functional, this architecture introduces a critical security vulnerability: the service account key is a long-lived credential. If such a key is leaked through a compromised secret, a malicious log dump, or an insider threat, it grants full, indefinite access to any GCP resource the service account is authorized to manage.

Workload Identity Federation (WIF) emerges as the professional standard for mitigating these risks. It shifts the authentication paradigm from "secret-based" to "trust-based." Instead of storing a permanent password (the JSON key), GitHub Actions leverages OpenID Connect (OIDC) to prove its identity to Google Cloud. This process allows the GitHub runner to exchange a short-lived OIDC token for a temporary GCP access token. These credentials are ephemeral, meaning they expire automatically after a short period, ensuring that if a token is intercepted, its utility to an attacker is severely limited. This architectural shift reduces the complexity of credential rotation and eliminates the risk associated with long-term credential leakage.

The Technical Architecture of Workload Identity Federation

Workload Identity Federation functions as a bridge between an external identity provider (IdP), such as GitHub, and Google Cloud's Identity and Access Management (IAM) system. The process is dynamic and occurs entirely at runtime, ensuring that permissions are granted only when a specific workflow is executing.

The operational flow of a WIF-enabled authentication request follows a precise sequence of cryptographic exchanges:

  1. OIDC Token Request: When a GitHub Actions workflow is triggered, the runner requests a unique identity token from GitHub's OIDC provider. This token is not a generic password but a signed assertion containing metadata about the specific execution environment. This metadata includes the repository name, the workflow details, and the event that triggered the run.

  2. Token Signing: GitHub signs the token to ensure its integrity. This prevents attackers from spoofing the identity of a repository to gain unauthorized access to GCP.

  3. Transmission to GCP: The workflow sends this signed OIDC token to the Google Cloud IAM service.

  4. Validation via Workload Identity Pool: Google Cloud does not validate the token in a vacuum. It forwards the request to a pre-configured Workload Identity Pool. This pool acts as the gateway and evaluates the token against "trust conditions" defined by the administrator. These conditions verify if the request originates from an approved organization, a specific repository, or a designated branch.

  5. Token Exchange: If the trust conditions are satisfied, the Workload Identity Pool maps the external GitHub identity to a specific GCP service account.

  6. Access Grant: The system generates a short-lived GCP credential. The workflow now possesses the authorization to interact with GCP services (such as Cloud Run, GCS, or BigQuery) as permitted by the IAM roles assigned to that service account. Once the workflow completes or the token expires, the access is automatically revoked.

Transitioning from Static Keys to Federated Identities

The move toward WIF is driven by the inherent failures of static service account keys. To understand the necessity of WIF, one must analyze the drawbacks of the legacy approach.

Feature Static Service Account Keys Workload Identity Federation
Credential Lifespan Long-lived / Permanent Short-lived / Ephemeral
Storage Method Stored as GitHub Secrets (JSON) No keys stored in GitHub
Rotation Requirement Manual or automated rotation needed No rotation required (automatic)
Security Risk High (Leakage leads to full compromise) Low (Tokens expire quickly)
Auditability Difficult to track specific workflow users Precise mapping of OIDC claims
Management Overhead High (Key lifecycle management) Low (Policy-based trust)

By removing the need for JSON keys, organizations eliminate the "credential management" burden. There is no longer a need to worry about rotating keys every 90 days or managing the fallout of a leaked secret. The security posture shifts from managing "secrets" to managing "trust policies."

Step-by-Step Configuration of Google Cloud for WIF

Configuring Google Cloud to trust GitHub Actions requires a series of administrative steps to establish the identity bridge.

Creating the Workload Identity Pool

The first step is the creation of a Workload Identity Pool. This entity serves as the organizational container for external identities.

gcloud iam workload-identity-pools create "github-pool" \ --project="my-project" \ --location="global" \ --display-name="Pool for GitHub Actions OIDC authentication"

The pool serves as the bridge. By defining the location as global, the provider is accessible across different regions, ensuring the CI/CD pipeline is not tied to a specific geographical data center.

Establishing the OIDC Identity Provider

Once the pool exists, a provider must be created within that pool. This tells GCP exactly how to validate tokens coming from GitHub's servers.

gcloud iam workload-identity-pools providers create-oidc "github-provider" \ --project="my-project" \ --location="global" \ --workload-identity-pool="github-pool" \ --display-name="GitHub OIDC Provider" \ --issuer-uri="https://token.actions.githubusercontent.com" \ --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 == 'my-github-org'"

Analysis of the configuration flags:

  • issuer-uri: This is the official URL of GitHub's OIDC token issuer. GCP uses this to verify that the token was indeed signed by GitHub.
  • attribute-mapping: This maps the claims inside the GitHub OIDC token to Google's internal identity format. For example, assertion.repository identifies which project is requesting access.
  • attribute-condition: This is a critical security filter. By specifying assertion.repository_owner == 'my-github-org', the administrator ensures that only repositories owned by their specific organization can exchange tokens for GCP credentials, preventing any random GitHub user from attempting to authenticate against the pool.

Linking the Service Account

After the provider is configured, the external identity must be mapped to a GCP service account that possesses the necessary IAM roles. This is done by granting the roles/iam.workloadIdentityUser role to the external identity.

The provider resource name is required for this link. The format generally follows: projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-pool/providers/github-provider.

Implementing the GitHub Actions Workflow

To successfully utilize WIF, the GitHub workflow file (.yml) must be configured with specific permissions and use the correct authentication actions.

Required Workflow Permissions

A common point of failure in WIF implementation is the omission of the permissions block. By default, GitHub Actions tokens do not have the authority to request an OIDC token.

The following permissions are mandatory:

  • contents: read: Allows the action to check out the code.
  • id-token: write: This is the critical permission. It allows the workflow to request the OIDC token from GitHub's provider, which is then sent to GCP.

Authentication Logic with google-github-actions/auth

The authentication process is handled by the google-github-actions/auth action. This action manages the exchange of the OIDC token for the GCP access token.

yaml - name: Authenticate to Google Cloud id: auth uses: google-github-actions/auth@v2 with: workload_identity_provider: "projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-pool/providers/github-provider" service_account: "[email protected]"

In this configuration:
- workload_identity_provider: The full resource path to the provider created in the previous steps.
- service_account: The email of the service account that the WIF provider will impersonate.

Deploying to Google Cloud Run

A practical application of this secure authentication is deploying services to Cloud Run. This can be achieved using the google-github-actions/deploy-cloudrun action.

Integration with deploy-cloudrun

The deploy-cloudrun action allows for deployment from a container image or directly from source code. It is important to note that this action runs using Node 24; therefore, any self-hosted runners must support this version.

Example complete workflow:

```yaml
name: Deploy to GCP
on:
push:
branches: [main]

permissions:
contents: read
id-token: write

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

  - name: Authenticate to Google Cloud
    id: auth
    uses: google-github-actions/auth@v2
    with:
      workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
      service_account: '[email protected]'

  - id: 'deploy'
    uses: 'google-github-actions/deploy-cloudrun@v3'
    with:
      service: 'hello-cloud-run'
      image: 'us-docker.pkg.dev/cloudrun/container/hello:latest'

  - name: 'Use output'
    run: 'curl "${{ steps.deploy.outputs.url }}"'

```

Analysis of the Deployment Process

In the provided example, the deploy-cloudrun action utilizes the authentication context established by the auth action.

  • service: This is an optional ID of the service. If not provided, metadata or job identifiers must be used.
  • image: The path to the container image in the Google Artifact Registry.
  • Output Handling: The action provides the resulting service URL as an output, which can be accessed via ${{ steps.deploy.outputs.url }}, allowing subsequent steps to verify the deployment via curl or other health check tools.

Final Technical Analysis and Conclusion

The transition from static service account keys to Workload Identity Federation represents a fundamental shift in the security posture of cloud-native deployments. By utilizing OIDC tokens, organizations move from a "permanent secret" model to a "temporary trust" model.

The technical impact is three-fold. First, it eliminates the operational overhead of key rotation and the risk of credential leakage. Second, it provides granular control; by using attribute-conditions, administrators can restrict access not just to an organization, but to specific repositories or branches. Third, it improves auditability, as the identity of the requesting workload is cryptographically verified by Google Cloud.

For developers, the implementation requires a careful orchestration of GCP IAM settings and GitHub workflow permissions. The necessity of the id-token: write permission cannot be overstated, as its absence will result in the failure of the google-github-actions/auth action to retrieve the necessary OIDC token.

While the deploy-cloudrun action is a powerful tool for automating deployments, users should be aware that it is not an officially supported Google product covered by a Google Cloud support contract. Despite this, it remains the industry standard for integrating GitHub Actions with Cloud Run.

Ultimately, WIF is the only scalable and secure way to handle non-GCP system authentication. By removing long-lived credentials from the pipeline, the attack surface is significantly reduced, and the integrity of the deployment pipeline is ensured through short-lived, verifiable identity assertions.

Sources

  1. OneUptime - How to Set Up Workload Identity Federation
  2. Firefly AI - Setting Up Workload Identity Federation
  3. GitHub - deploy-cloudrun Action

Related Posts