Artifact RegistryへのDockerプッシュ権限エラーの解決
問題の概要
GitHub Actionsを使用してGoogle CloudのArtifact RegistryにDockerイメージをプッシュしようとする際に、次のエラーが発生します:
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つの根本原因から発生します:
- 使用しているサービスアカウントにArtifact Registryへの書き込み権限がない
- Dockerクライアントが正しく認証されていない
以下でそれぞれのケースに対する解決策を詳しく説明します。
Artifact Registryとは
Google CloudのArtifact Registryは、Dockerイメージ、Mavenパッケージ、npmパッケージなどのバイナリアーティファクトを管理するためのフルマネージドサービスです。Container Registryの後継となるサービスで、複数のリポジトリタイプや地理的位置をサポートしています。
解決策1: IAM権限の設定確認
最初に、サービスアカウントに適切な権限が付与されていることを確認します:
# 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コンソールで確認する手順:
- Artifact Registryコンソールにアクセス
- 対象のリポジトリを選択 →「権限」タブを開く
- 使用しているサービスアカウントに
Artifact Registryライター
ロールが付与されているか確認 - 存在しない場合は「プリンシパルを追加」でアカウントとロールを設定
警告
roles/artifactregistry.writer
ロールが不足しているとプッシュ権限エラーが発生します。roles/owner
などより広範なロールで代用することは非推奨です(セキュリティ上のリスクがあります)
ロールが正しく付与されているかIAMポリシートラブルシューターで確認:
https://console.cloud.google.com/iam-admin/troubleshooter?orgonly=true&project=your-project-id
- プリンシパル:サービスアカウントのメールアドレスを指定
- リソース:対象のArtifact Registryリソースを選択
- 権限:
artifactregistry.repositories.uploadArtifacts
を選択
解決策2: 正しいDocker認証方法の実装
権限設定が正しいにも関わらずエラーが発生する場合、GitHub Actions内での認証方法に問題があります。以下に効果的な方法を2つ紹介します。
方法A: docker/login-actionを活用する(推奨)
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アクセストークンを使用する
- 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 login
にauth_token
を渡してしまうケース:
# ❌ 間違った例(auth_token を使用)
password: ${{ steps.auth.outputs.auth_token }}
# ✅ 正しい例(access_token を使用)
password: ${{ steps.auth.outputs.access_token }}
完全なサンプルワークフロー
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: 権限は正しいのに依然としてアクセス拒否
# gcloudのCLI設定を確認
gcloud config list
# 認証状態を確認
gcloud auth list
# リポジトリ作成状態を確認
gcloud artifacts repositories list --location=asia-south1
ケース2: WSL2環境での特有の問題
- gcloud CLIの再インストール
gcloud init
で再認証- 明示的にリージョンを指定:bash
gcloud auth configure-docker asia-south1-docker.pkg.dev
ケース3: Docker Snapインストール時の設定パス問題
# 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
ベストプラクティス
最小権限の原則:
- サービスアカウントには必要な権限のみ付与
Artifact Registryライター
+サービスアカウントトークン作成者
の組み合わせが理想
環境変数管理:
- プロジェクトIDやリージョンはGitHubリポジトリのSecrets/Variablesに保存
- 直接ワークフロー内に書かない
認証方法の選択:
- 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へのプッシュ権限エラーを解決する手順:
- IAM権限設定を確認(
roles/artifactregistry.writer
) - 認証方法を適切に実装
- 推奨:
docker/login-action
+access_token
- 代替:
gcloud auth print-access-token
パイプ方式
- 推奨:
- リージョン指定を厳密に実施
- 環境ごとの設定を確認(特にWSL/Docker Snap環境)
これらの対策を講じることで、GitHub Actionsからの安全で効率的なDockerイメージプッシュが可能になります。