I recently needed to push container images and Helm charts to Artifact Registry and wanted to use GitHub Actions. Looking around I found this action and this blog post describing how to use service accounts and keyless authentication using workload identity federation. Luckily, this blog post described all the individual steps for setting this up using the gcloud
CLI so it was straightforward adapting it to my Terraform workflow.
Terraform Configuration
See the Google blog post for more details on how the authentication actually works, here is the Terraform configuration:
locals {
# Your GCP project id
project_id = "<your google cloud project id>"
# The GitHub org (or username) where the actions will run
github_org = "<your org or username>"
# The individual repos that will be running actions that need to authenticate
github_repos = [
"<your repo>"
]
# IAM roles to assign to the Service Account
roles = [
"roles/artifactregistry.reader",
"roles/artifactregistry.writer",
]
}
# Create the Service Account
resource "google_service_account" "gh_actions_sa" {
account_id = "gh-actions"
display_name = "Service Account for GitHub Actions to push container images and Helm charts to Artifact Registry"
}
# Create a workload identity pool to associate the service account with
resource "google_iam_workload_identity_pool" "github" {
project = local.project_id
workload_identity_pool_id = "github-actions"
display_name = "github-actions"
description = "For GitHub Actions authentication"
}
# Create a workload identity provider for GitHub
resource "google_iam_workload_identity_pool_provider" "github" {
project = local.project_id
workload_identity_pool_id = google_iam_workload_identity_pool.github.workload_identity_pool_id
workload_identity_pool_provider_id = "github-provider"
display_name = "github-provider"
description = "OIDC identity pool provider for execute GitHub Actions"
# See. https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#understanding-the-oidc-token
attribute_condition = "assertion.repository_owner == '${local.github_org}'"
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.actor" = "assertion.actor"
"attribute.repository" = "assertion.repository"
"attribute.repository_owner" = "assertion.repository_owner"
}
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
allowed_audiences = []
}
}
# Allow the service account to authenticate with a GitHub action from each of the declared repos
resource "google_service_account_iam_member" "workload_identity_user" {
for_each = toset(local.github_repos)
service_account_id = google_service_account.gh_actions_sa.name
role = "roles/iam.workloadIdentityUser"
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github.name}/attribute.repository/${local.github_org}/${each.value}"
}
# Attach the roles that the Service Account will need
resource "google_project_iam_member" "sa_roles" {
for_each = toset(local.roles)
project = local.project_id
role = each.value
member = "serviceAccount:${google_service_account.gh_actions_sa.email}"
}
# This is the value you'll need for the GitHub Action authenticate step
output "service_account_email" {
description = "The Service Account email"
value = google_service_account.gh_actions_sa.email
}
# This is the value you'll need for the GitHub Action authenticate step
output "workload_identity_pool_name" {
description = "Workload Identity Pood Provider ID"
value = google_iam_workload_identity_pool_provider.github.name
}
GitHub Action Configuration
Once you provision all of the resources you will want to take the outputs and set them up as secrets for your GitHub Actions. This will then allow you to configure the following steps in your Actions:
name: Auth Example
jobs:
example:
runs-on: ubuntu-latest
# Required permissions for authenticating with GCP
# See https://github.com/google-github-actions/auth for details
permissions:
contents: 'read'
id-token: 'write'
steps:
- name: Checkout repository
uses: actions/checkout@v4
#
- name: Log in to Google Cloud
uses: google-github-actions/auth@v2
with:
service_account: '${{ secrets.SERVICE_ACCOUNT_EMAIL }}'
workload_identity_provider: '${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}'
With these steps you can authenticate to your GCP project with GitHub Actions in a scoped manner. There is additional hardening that can be done, but this is a starter for that.