Skip to content

Artifact RegistryへのDockerプッシュ権限エラーの解決

問題の概要

GitHub Actionsを使用してGoogle CloudのArtifact RegistryにDockerイメージをプッシュしようとする際に、次のエラーが発生します:

text
denied: Permission "artifactregistry.repositories.uploadArtifacts" denied on resource 
"projects/PROJECT_ID/locations/asia-south1/repositories/images" 
(or it may not exist) Error: Process completed with exit code 1.

このエラーは主に2つの根本原因から発生します:

  1. 使用しているサービスアカウントにArtifact Registryへの書き込み権限がない
  2. Dockerクライアントが正しく認証されていない

以下でそれぞれのケースに対する解決策を詳しく説明します。

Artifact Registryとは

Google CloudのArtifact Registryは、Dockerイメージ、Mavenパッケージ、npmパッケージなどのバイナリアーティファクトを管理するためのフルマネージドサービスです。Container Registryの後継となるサービスで、複数のリポジトリタイプや地理的位置をサポートしています。

解決策1: IAM権限の設定確認

最初に、サービ​​スアカウントに適切な権限が付与されていることを確認します:

hcl
# IAMポリシーの例(最低限必要な権限)
resource "google_artifact_registry_repository_iam_binding" "writer" {
  project    = "your-project-id"
  location   = "asia-south1"
  repository = "images"
  
  role    = "roles/artifactregistry.writer"
  members = [
    "serviceAccount:your-service-account@your-project.iam.gserviceaccount.com"
  ]
}

Google Cloudコンソールで確認する手順:

  1. Artifact Registryコンソールにアクセス
  2. 対象のリポジトリを選択 →「権限」タブを開く
  3. 使用しているサービスアカウントにArtifact Registryライターロールが付与されているか確認
  4. 存在しない場合は「プリンシパルを追加」でアカウントとロールを設定

警告

roles/artifactregistry.writerロールが不足しているとプッシュ権限エラーが発生します。roles/ownerなどより広範なロールで代用することは非推奨です(セキュリティ上のリスクがあります)

ロールが正しく付与されているかIAMポリシートラブルシューターで確認:

sql
https://console.cloud.google.com/iam-admin/troubleshooter?orgonly=true&project=your-project-id
  1. プリンシパル:サービスアカウントのメールアドレスを指定
  2. リソース:対象のArtifact Registryリソースを選択
  3. 権限:artifactregistry.repositories.uploadArtifactsを選択

解決策2: 正しいDocker認証方法の実装

権限設定が正しいにも関わらずエラーが発生する場合、GitHub Actions内での認証方法に問題があります。以下に効果的な方法を2つ紹介します。

方法A: docker/login-actionを活用する(推奨)

yaml
steps:
- name: Authenticate to Google Cloud
  id: auth
  uses: google-github-actions/auth@v1
  with:
    token_format: access_token
    workload_identity_provider: projects/PROJECT_ID/locations/global/workloadIdentityPools/POOL/providers/PROVIDER
    service_account: SA_EMAIL@PROJECT.iam.gserviceaccount.com

- name: Login to Artifact Registry
  uses: docker/login-action@v3  # Docker公式ログインアクション
  with:
    registry: ${{ vars.REGION }}-docker.pkg.dev
    username: oauth2accesstoken  # 固定値
    password: ${{ steps.auth.outputs.access_token }}  # 認証情報アクセストークン

この方法の特徴:

  • Googleの認証後、直接Dockerクライアントを認証
  • access_tokenをpasswordとして使用(auth_tokenではない点に注意)
  • リージョンは環境変数で管理可能

方法B: gcloud CLIアクセストークンを使用する

yaml
- name: Authenticate Docker using gcloud
  run: |-
    # アクセストークン取得&Dockerログイン
    echo "$(gcloud auth print-access-token)" | \
    docker login -u oauth2accesstoken --password-stdin \
    https://asia-south1-docker.pkg.dev  # 実際のリージョンに変更

この方法の注意点:

  • gcloud CLIが正しくインストール&初期化されている必要あり
  • Dockerの設定ファイルパス問題が発生する可能性あり(特にWSL環境)
  • 一時的なアクセストークンを使用するためセキュリティ面では問題なし

よくある間違い

docker loginauth_tokenを渡してしまうケース:

yaml
# ❌ 間違った例(auth_token を使用)
password: ${{ steps.auth.outputs.auth_token }} 

# ✅ 正しい例(access_token を使用)
password: ${{ steps.auth.outputs.access_token }}

完全なサンプルワークフロー

yaml
name: Build and Push to Artifact Registry

on:
  push:
    branches: [master]

env:
  PROJECT_ID: 'your-gcp-project'
  REGION: 'asia-south1'
  REPOSITORY: 'images'
  IMAGE_NAME: 'my-app'

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: 'read'
      id-token: 'write'  # Workload Identityに必須

    steps:
    - name: Checkout Code
      uses: actions/checkout@v4

    - id: auth
      name: Authenticate to Google Cloud
      uses: google-github-actions/auth@v1
      with:
        workload_identity_provider: 'projects/${{ env.PROJECT_ID }}/locations/global/workloadIdentityPools/github/providers/gh-provider'
        service_account: 'sa-name@${{ env.PROJECT_ID }}.iam.gserviceaccount.com'
        token_format: 'access_token'  # Docker認証に必要

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3

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

    - name: Build and Push Docker Image
      env:
        TAG: ${{ github.sha }}
      run: |
        docker build -t ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:$TAG .
        docker push ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:$TAG

トラブルシューティング

ケース1: 権限は正しいのに依然としてアクセス拒否

bash
# gcloudのCLI設定を確認
gcloud config list
# 認証状態を確認
gcloud auth list
# リポジトリ作成状態を確認
gcloud artifacts repositories list --location=asia-south1

ケース2: WSL2環境での特有の問題

  1. gcloud CLIの再インストール
  2. gcloud initで再認証
  3. 明示的にリージョンを指定:
    bash
    gcloud auth configure-docker asia-south1-docker.pkg.dev

ケース3: Docker Snapインストール時の設定パス問題

bash
# Snap版Dockerの削除
sudo snap remove docker

# 公式インストールスクリプトで再インストール
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

ケース4: サービスアカウントの権限継承問題

プリンシパルに以下のロールを追加:

  • roles/iam.serviceAccountTokenCreator
  • roles/artifactregistry.writer

ベストプラクティス

  1. 最小権限の原則

    • サービスアカウントには必要な権限のみ付与
    • Artifact Registryライターサービスアカウントトークン作成者の組み合わせが理想
  2. 環境変数管理

    • プロジェクトIDやリージョンはGitHubリポジトリのSecrets/Variablesに保存
    • 直接ワークフロー内に書かない
  3. 認証方法の選択

    • Workload Identityを使用:キー流出リスクが低減
    • やむを得ずサービスアカウントキーを使う場合は:
      yaml
      - name: Docker Login with Service Account Key
        uses: docker/login-action@v3
        with:
          registry: ${{ vars.REGION }}-docker.pkg.dev
          username: _json_key
          password: ${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}  # Base64エンコードされた鍵

まとめ

Artifact Registryへのプッシュ権限エラーを解決する手順:

  1. IAM権限設定を確認(roles/artifactregistry.writer
  2. 認証方法を適切に実装
    • 推奨: docker/login-action + access_token
    • 代替: gcloud auth print-access-tokenパイプ方式
  3. リージョン指定を厳密に実施
  4. 環境ごとの設定を確認(特にWSL/Docker Snap環境)

これらの対策を講じることで、GitHub Actionsからの安全で効率的なDockerイメージプッシュが可能になります。