This guide explains how to use private Google Artifact Registry (GAR) images as Dev Container images when using GCP runners. With runner-native authentication, you can access private GAR repositories without manually managing credentials.

Prerequisites

Before you begin, ensure you have:
  • GCP runners deployed and configured for your Ona environments
  • GAR registry in the same GCP project as your runners (or with appropriate cross-project access)
  • gcloud CLI installed and authenticated with appropriate permissions to manage IAM policies
  • Runner name and project ID from your Ona runner configuration

Setting up Google Artifact Registry Access

Step 1: Create Container Registry Secret

  1. Navigate to Project > Secrets > New Secret in your Ona dashboard
  2. Select Container Registry Basic Auth from the type dropdown
  3. For the Registry hostname, enter your GAR registry hostname in the format: [region]-docker.pkg.dev Examples:
    • us-central1-docker.pkg.dev (for US Central region)
    • europe-west1-docker.pkg.dev (for Europe West region)
    • asia-southeast1-docker.pkg.dev (for Asia Southeast region)
  4. When you enter a GAR registry hostname, the username and password fields will automatically be filled with runner-native to indicate that native runner authentication will be used
  5. Click Add
Runner-native Authentication: When you enter a GAR hostname, Ona automatically detects this as a supported registry and enables runner-native authentication, eliminating the need for manual credential management.

Step 2: Configure Service Account Permissions

Your GCP runner creates an environment VM service account that needs access to your GAR repositories.

Identify Your Environment Service Account

Your environment service account follows this naming pattern:
{RUNNER_NAME}-env-vm@{PROJECT_ID}.iam.gserviceaccount.com
For example, if your runner is named gcp-runner-01 in project my-project-123, the service account would be:
gcp-runner-01-env-vm@my-project-123.iam.gserviceaccount.com
Use the gcloud command to grant access to specific repositories:
# Set your configuration variables
PROJECT_ID="your-project-id"
RUNNER_NAME="your-runner-name"
REGION="your-region"
REPO_NAME="your-repository-name"

# The environment VM service account (automatically created by your runner)
ENVIRONMENT_VM_SERVICE_ACCOUNT="${RUNNER_NAME}-env-vm@${PROJECT_ID}.iam.gserviceaccount.com"

# Grant repository access
gcloud artifacts repositories add-iam-policy-binding $REPO_NAME \
    --location=$REGION \
    --member="serviceAccount:${ENVIRONMENT_VM_SERVICE_ACCOUNT}" \
    --role="roles/artifactregistry.reader"

Alternative: Project-level Access

For broader access, you can grant project-level permissions:
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:${ENVIRONMENT_VM_SERVICE_ACCOUNT}" \
    --role="roles/artifactregistry.reader"

Step 3: Configure Your Dev Container

Update your .devcontainer/devcontainer.json to use your private GAR image:
{
    "name": "My Dev Container",
    "image": "us-central1-docker.pkg.dev/my-project-123/my-repo/my-image:latest",
    "features": {
        // Your features here
    }
}

Required IAM Roles

The minimum required role for accessing GAR repositories is:
roles/artifactregistry.reader
For more granular control, you can create a custom role with these specific permissions:
artifactregistry.repositories.downloadArtifacts
artifactregistry.repositories.get
artifactregistry.repositories.list

Verification

To verify the permissions are correctly configured:

Check Repository-level Permissions

gcloud artifacts repositories get-iam-policy $REPO_NAME --location=$REGION

Check Project-level Permissions

gcloud projects get-iam-policy $PROJECT_ID \
    --flatten="bindings[].members" \
    --format="table(bindings.role)" \
    --filter="bindings.members:${ENVIRONMENT_VM_SERVICE_ACCOUNT}"

Verify Service Account Exists

# List all service accounts in your project
gcloud iam service-accounts list --project=$PROJECT_ID

# Look for accounts matching the pattern: {RUNNER_NAME}-env-vm@{PROJECT_ID}.iam.gserviceaccount.com

Troubleshooting

Image Pull Failures

If you’re experiencing image pull failures, verify:
  1. Service account name is correct:
    # List all service accounts in your project
    gcloud iam service-accounts list --project=$PROJECT_ID
    
  2. IAM permissions are correctly applied:
    # Check repository-level permissions
    gcloud artifacts repositories get-iam-policy $REPO_NAME --location=$REGION
    
  3. Repository exists and is accessible:
    # List repositories in the region
    gcloud artifacts repositories list --location=$REGION
    

Authentication Errors

If you see authentication errors in your environment logs:
  • Ensure the GAR hostname format is correct: [region]-docker.pkg.dev
  • Verify that your runner and registry are in the same project or have cross-project access configured
  • Check that the service account has the minimum required role: roles/artifactregistry.reader
  • Confirm the service account name matches the expected pattern

Common Error Messages

“Failed to pull image”
  • Check that the image exists in the specified repository
  • Verify the image tag is correct
  • Ensure the service account has pull permissions
“Authentication required”
  • Confirm the container registry secret is properly configured
  • Verify the service account has the correct IAM roles
  • Check that the GAR hostname matches your registry region

Limitations

  • GCP runners only: GAR runner-native registry support is only available for GCP runners
  • Same project recommended: Your GCP runners and GAR registry should be in the same project for simplest configuration
  • Environment recreation required: Existing environments must be recreated to apply changes to GAR permissions
  • No automatic docker login: Unlike basic auth registries, GAR doesn’t automatically log you into the registry from within the environment. Use gcloud auth or Ona OIDC for additional registry access from within your environment

Next Steps