Github OpenID Connect

Overview

OpenID Connect (OIDC) enables GitHub Actions workflows to access Google Cloud Platform (GCP) resources without storing long-lived GCP credentials as GitHub secrets. This approach enhances security by eliminating the need for persistent credential storage.

This guide provides:

  • End-to-end configuration of GitHub Actions OpenID Connect authentication with GCP using Workload Identity Federation.

  • Terraform Plan and Apply workflow to deploy Google Cloud Infrastructure.

GitHub Actions Workload Identity Federation Authentication

This guide uses the google-github-actions/auth GitHub action to handle OIDC authentication with GCP.

For each GitHub Actions job, an OIDC token is requested from GitHub’s OIDC provider. The provider responds with an automatically generated JSON Web Token (JWT). This JWT is unique for each GitHub Workflow job execution and contains claims about the job’s identity and context.

Google GitHub Actions

google-github-actions/auth provides 3 methods to authenticate with Google Cloud using Workload Identity Federation:

  1. Workload Identity Federation Direct

  2. Workload Identity Federation Service Account

  3. Service Account Key JSON

Workload Identity Federation Direct is the recommended approach for this guide. It provides direct authentication of the GitHub workflow job to GCP without an intermediate service account. The google-github-actions/auth action uses the GitHub OIDC token to authenticate as the workload identity associated with the GitHub repository.

Workload Identity Federation Service Account is similar to the direct method but introduces an intermediate GCP service account. In this approach, the GitHub workflow impersonates the intermediate service account, which has been granted the necessary permissions on GCP resources. While this method adds an extra authentication step, it offers no significant advantages over direct authentication.

Service Account Key JSON uses a JSON private key file downloaded from GCP instead of GitHub’s OIDC token. This method eliminates the need to configure Workload Identity Federation. However, it is less secure because it requires storing long-lived credentials as GitHub secrets.

The difference between Workload Identity Federation Direct and Workload Identity Federation Service Account is illustrated in the following diagrams:

Workload Identity Federation Direct

../../_images/github-wif-direct.svg

Workload Identity Federation Service Account

../../_images/github-wif-service.svg

This guide focuses on the Workload Identity Federation Direct authentication method.

Workload Identity Federation Direct Setup

  1. Define Terraform Locals Variables

Local Variables
locals {
  github_owner_id   = "'59314971'"            # Replace with GitHub `repository_owner_id`
  github_repository = "kborovik/google-infra" # Replace with GitHub `repository_name`
}
  1. Create GCP Workload Identity Pool

Workload Identity Pool
resource "google_iam_workload_identity_pool" "github" {
  workload_identity_pool_id = "github"
  display_name              = "GitHub OIDC"

  lifecycle {
    prevent_destroy = true
  }
}
  1. Create GCP Workload Identity Pool Provider

When a GitHub Actions job runs, it presents an OIDC token to the Google Cloud OIDC provider for authentication. The Google Cloud provider validates this token by checking:

  • The token was issued by the trusted GitHub OIDC provider

  • The token’s assertion.repository claim matches the GitHub repository name

  • The assertion.repository_owner_id claim in the attribute condition matches the GitHub repository owner ID

Warning

Security Warning

GitHub Actions OIDC tokens may contain claims that are not unique across different organizations or repositories. This lack of uniqueness could potentially allow tokens from other sources to establish an identity. To mitigate this risk, always use an attribute_condition to restrict access to tokens issued by your specific GitHub organization.

Use a unique identifier for your organization, such as the repository_owner_id, instead of relying solely on the repository name or other potentially non-unique values.

For more information on configuring OIDC trust definitions, see GitHub OIDC Token.

Workload Identity Pool Provider
resource "google_iam_workload_identity_pool_provider" "github" {
  workload_identity_pool_provider_id = "google-infra"
  display_name                       = "GitHub Repo google-infra"
  workload_identity_pool_id          = google_iam_workload_identity_pool.github.workload_identity_pool_id
  attribute_mapping = {
    "attribute.repository" = "assertion.repository"
    "google.subject"       = "assertion.sub"
  }
  attribute_condition = "assertion.repository_owner_id == ${local.github_owner_id}"

  oidc {
    issuer_uri = "https://token.actions.githubusercontent.com"
  }

  lifecycle {
    prevent_destroy = true
  }
}
  1. Grant IAM Permissions to Workload Identity

IAM Permissions to Workload Identity
locals {
  github_aim_roles = [
    "roles/editor",
    "roles/iam.securityAdmin",
  ]
}

resource "google_project_iam_member" "github_principal_set" {
  count   = length(local.github_aim_roles)
  project = var.google_project
  role    = local.github_aim_roles[count.index]
  member  = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github.name}/attribute.repository/${local.github_repository}"
}

GitHub Actions Workflow

  1. Retrieve the complete identifier for the Workload Identity Pool

List Workload Identity Pools
(0) > gcloud iam workload-identity-pools list \
        --location=global
---
displayName: GitHub OIDC
name: projects/320561780581/locations/global/workloadIdentityPools/github
state: ACTIVE
List Workload Identity Pools Providers
(0) > gcloud iam workload-identity-pools providers list \
        --location=global \
        --workload-identity-pool=github
---
attributeCondition: assertion.repository_owner_id == '59314971'
attributeMapping:
  attribute.repository: assertion.repository
  google.subject: assertion.sub
displayName: GitHub Repo google-infra
name: projects/320561780581/locations/global/workloadIdentityPools/github/providers/google-infra
oidc:
  issuerUri: https://token.actions.githubusercontent.com
state: ACTIVE
  1. Configure Workload Identity Provider in GitHub Actions Workflow

After retrieving the Workload Identity Provider ID, incorporate it into your GitHub Actions workflow. This step is crucial for establishing the connection between your GitHub repository and Google Cloud Platform.

  • Use google_project value as the project_id value

  • Use projects/320561780581/locations/global/workloadIdentityPools/github/providers/google-infra value as the workload_identity_provider value

GitHub Actions
name: lab5-gcp-dev1
run-name: lab5-gcp-dev1

env:
  google_project: lab5-gcp-dev1
  workload_identity_provider: projects/320561780581/locations/global/workloadIdentityPools/github/providers/google-infra

jobs:
  terraform-plan:
    runs-on: ubuntu-latest
    steps:
      - id: checkout
        name: Code Checkout
        uses: actions/checkout@v4
      - id: auth
        name: Google Cloud Authentication
        uses: google-github-actions/auth@v2
        with:
          project_id: ${{ env.google_project }}
          workload_identity_provider: ${{ env.workload_identity_provider }}
  1. Run GitHub Pipeline

../../_images/github-pic1.webp