[Accessing Private Google Artifact Registry With Poetry: Local and Docker Setup]

Analyze with AI

Get AI-powered insights from this Mad Devs tech article:

Before you start

The setup described here uses Poetry >= 1.7.1, keyring >= 24.0.0, and keyrings.google-artifactregistry-auth >= 1.0.0. A few updates worth noting:

  • keyrings.google-artifactregistry-auth has been superseded by google-auth-based credential helpers in newer Poetry versions. If you encounter authentication issues with the keyring approach on Python 3.12+, try running python -m keyrings.google_artifactregistry_auth explicitly to verify the keyring backend is correctly registered.
  • Docker BuildKit is now enabled by default in Docker Desktop 4.x+ and Docker Engine 23+. The --mount=type=secret syntax used in this guide requires BuildKit and will work out of the box without setting DOCKER_BUILDKIT=1 explicitly.
  • In January 2025, Google patched the ImageRunner vulnerability in Cloud Run, which allowed unauthenticated access to private Artifact Registry images under certain IAM conditions. If your GAR repository was accessible via Cloud Run before January 28 2025, it is worth auditing your IAM bindings to confirm no unintended access was granted.

Accessing a private Google Artifact Registry locally: Python and Docker

When building Python applications with Poetry in a Docker container, we sometimes encounter issues accessing private packages stored in the Google Artifact Registry (GAR). Locally, this challenge arises because docker build cannot directly handle the Google Cloud credentials in the same way as our CI/CD pipeline, where we leverage service accounts and the Kaniko action for secure builds.

To resolve this, we'll cover two approaches: keyring-based authentication for local Python development using keyrings.google-artifactregistry-auth, and Docker Compose build secrets for containerised builds – both without exposing GCP credentials in the image.


Non-containerized

This approach uses keyrings.google-artifactregistry-auth to allow Poetry to authenticate with your private GAR Python repository automatically via application default credentials — no manual token passing required.

Pre-requirements

  • Python ^3.12
  • Poetry ^1.7.1
  • Google Cloud SDK ^489.0.0
  • Keyring ^24.0.0
  • keyrings.google-artifactregistry-auth ^1.0.0
  • Read access to your GAR Python repository
  • Logged into GCP (gcloud auth application-default login)

Setup

1. Keyring setup

Install keyring support for Google Artifact Registry:

pip install keyring
pip install keyrings.google-artifactregistry-auth

2. Connect Poetry to your GAR repo

Access to the private repository in the Google Artifact Registry can be managed through Poetry. First, configure a custom source in Poetry for the GAR repository by running:

poetry source add --priority=explicit <PACKAGE_NAME> https://<REGION>-python.pkg.dev/<PROJECT>/<REGISTRY>/simple

Note: Be sure to append /simple to the repository URL for compatibility.

Now you can install packages from your private repo:

poetry add --source <PACKAGE_NAME> [email protected]

Notes

In some cases, accessing the repository may require setting an explicit OAuth token for authentication in Poetry. Use the following command to configure this globally in Poetry:

poetry config http-basic.<PACKAGE_NAME> oauth2accesstoken $(gcloud auth print-access-token)

Containerized

Pre-requirements

  • Docker ^20.10
  • Docker Compose ^2.0
  • Google Cloud SDK ^489.0.0
  • Read access to your GAR Python repository
  • Logged into GCP (gcloud auth application-default login)

Setup

1. Secrets configuration

First, define a secret in docker-compose.yaml using the local path to your credentials file:

secrets:
  gcloud_credentials:
    file: ~/.config/gcloud/application_default_credentials.json
  • We define gcloud_credentials.file as a consistent path for Unix-like environments in docker-compose.yaml:
  • This configuration uses Docker Compose build secrets to securely pass the application_default_credentials.json file from your local machine to the build context – credentials never end up in the image layers or the build cache.

2. Dockerfile adjustments

In the Dockerfile, we handle credentials with the following setup:

ARG GOOGLE_APPLICATION_CREDENTIALS
ENV GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS}

RUN --mount=type=secret,id=gcloud_credentials \
    mkdir -p $(dirname ${GOOGLE_APPLICATION_CREDENTIALS}) && \
    cp /run/secrets/gcloud_credentials ${GOOGLE_APPLICATION_CREDENTIALS}
  • --mount=type=secret,id=gcloud_credentials: Securely mounts the credentials during the build process.
  • GOOGLE_APPLICATION_CREDENTIALS: Specifies the credential file's path within the container.

3. Service configurations

Here, gcloud_credentials is the secret mounted at build time, as specified in the secrets configuration.

some-service:
  build:
    context: .
    dockerfile: ./Dockerfile.local
    args:
      GOOGLE_APPLICATION_CREDENTIALS: /tmp/application_default_credentials.json
    secrets:
      - gcloud_credentials

Usage

Just run:

docker-compose up --build

Conclusion

This approach allows local Docker builds to access private GAR resources securely, ensuring that credentials are handled appropriately and remain protected.