Skip to content

Instantly share code, notes, and snippets.

@esgn
Last active June 26, 2024 14:15
Show Gist options
  • Save esgn/1df3ce6da7e7b3b7c262f8dd88e18da9 to your computer and use it in GitHub Desktop.
Save esgn/1df3ce6da7e7b3b7c262f8dd88e18da9 to your computer and use it in GitHub Desktop.
How to push a Docker image to Google Artifact Registry with a GitHub Action without using a Service Account

How to push a Docker image to Google Artifact Registry with a GitHub Action without using a Service Account

This how I managed to push a Docker image in a Google Cloud Artifact Registry using a GitHub Actions workflow without using a GCP Service Account.

Before using this tutorial make sure you have :

  • A GitHub repository containing a Dockerfile
  • A GCP project with sufficient permissions to make changes to it
  • The gcloud tool installed, authenticated and configured to use the GCP project. We will not use the --project flag in the following gcloud commands.

Create an Artifact Registry of Docker type

Give the new Artifact Registry the name and location of your choice.

# Example
# DOCKER_REGISTRY_NAME = "my-registry"
# DOCKER_REGISTRY_LOCATION = "europe-west9"

gcloud artifacts repositories create "${DOCKER_REGISTRY_NAME}" \
--repository-format="docker" \
--location="${DOCKER_REGISTRY_LOCATION}" \

Create a Workload Identity Pool

The following setup is derived from the documentation of the Google auth GitHub Action

First create a Workload Identity Pool named github (feel free to change its name)

gcloud iam workload-identity-pools create "github" \
  --location="global" \
  --display-name="GitHub Actions Pool"

Create a Workload Identity Pool Provider

Using GitHub OIDC server, create a Workload Identity Pool Provider named my-gh-repo (feel free to change its name) which includes a condition so that we are limiting what repository will be able to use it. Here, we're limiting to GitHub repositories owned by an user or an organization.

Note that we're also defining the mapping between attributes from authentication credentials issued by GitHub and Google Cloud attributes (--attribute-mapping). We will use these attributes at the next step.

gcloud iam workload-identity-pools providers create-oidc "my-gh-repo" \
--location="global" \
--workload-identity-pool="github" \
--display-name="My GitHub repo 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 == '${GH_REPO_OWNER}'" \
--issuer-uri="https://token.actions.githubusercontent.com"

Give repository the permission to push to Artifact Registry

Here we're giving the permission to GitHub repository owner_name/repository_name to push into the artifact registry we created at the beginning.
Practically speaking we're filtering on the attribute.repository attribute using a principalSet expression.

Note that the GitHub repository name must include the owner (user or organization).

# Set the FULL GitHub repository name that will get the rights to push Docker images to Artifact registry
GH_REPO_NAME="owner_name/repository_name"

# Get full name of the Workload Identity Pool (e.g projects/123456789/locations/global/workloadIdentityPools/github)
WIP_NAME=$(gcloud iam workload-identity-pools describe "github" --format="value(name)" --location="global")

gcloud artifacts repositories add-iam-policy-binding ${DOCKER_REGISTRY_NAME} \
  --role="roles/artifactregistry.writer" \
  --member="principalSet://iam.googleapis.com/${WIP_NAME}/attribute.repository/${GH_REPO_NAME}" \
  --location="${DOCKER_REGISTRY_LOCATION}"

Create a GitHub Actions workflow

Get Workload Identity Pool Provider full name

For this step, we will need the full name of the Workload Identity Pool Provider. You can obtain it using the following command :

# This command will return a string of the following type projects/123456789/locations/global/workloadIdentityPools/github/providers/my-gh-repo

gcloud iam workload-identity-pools providers describe "my-gh-repo" \
--workload-identity-pool="github"  \
--location="global" \
--format="value(name)"

Add the GitHub Actions workflow

Add a new YAML file in .github/workflows inside your repository with the following minimal content.

You'll have to replace the following elements :

  • <GCP_PROJECT_NAME>: The name of your GCP project
  • <WIP_PROVIDER_FULL_NAME>: The Workload Identity Pool Provider full name (e.g projects/123456789/locations/global/workloadIdentityPools/github/providers/my-gh-repo)
  • <DOCKER_REGISTRY_LOCATION>: The location of the Artifact Registry you create (e.g europe-west9)
  • <DOCKER_IMAGE_NAME>: The name of the Docker image you want to push (e.g myorg/myimage)
  • <DOCKER_IMAGE_TAG>: The tag that will be set on the produced Docker image (e.g latest)

Note that ${{ steps.auth.outputs.auth_token }} will automatically be replaced by GitHub with the result of the Authenticate with Google Cloud step.

name: "Push Docker image to GCP GAR"

on:
  push:

jobs:
  docker-release:
    name: "Push Docker Image to Google Artifact Registry"
    runs-on: ubuntu-latest

    permissions:
      contents: 'read'
      id-token: 'write'

    steps:
      - id: checkout
        name: Checkout
        uses: actions/checkout@v2

      - id: auth
        name: Authenticate with Google Cloud
        uses: google-github-actions/auth@v2
        with:
          project_id: <GCP_PROJECT_NAME>
          workload_identity_provider: <WIP_PROVIDER_FULL_NAME>

      - name: Login to Artifact Registry
        uses: docker/login-action@v3
        with:
          registry: <DOCKER_REGISTRY_LOCATION>-docker.pkg.dev
          username: oauth2accesstoken
          password: ${{ steps.auth.outputs.auth_token }}

      - id: docker-push-tagged
        name: Tag Docker image and push to Google Artifact Registry
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
             <DOCKER_REGISTRY_LOCATION>-docker.pkg.dev/<GCP_PROJECT_NAME>/<DOCKER_REGISTRY_NAME>/<DOCKER_IMAGE_NAME>:<DOCKER_IMAGE_TAG>

Commit and the workflow will build and push the Docker Image to GCP Artifact Registry.

Final thoughts

It's still painfull but we're getting rid of a dedicated Service Account. Let me know if you identify some mistakes or improvements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment