Skip to main content

OIDCを利用したGitHub ActionsからGoogle CloudへのDocker Pushの設定方法

GitHub ActionsからDocker ImageをGoogle Cloudにpushしたい

2022年現在だとOpenID Connect(OIDC)トークンを利用した方法がセキュアなようです。

GitHub Actions からのキーなしの認証の有効化 | Google Cloud Blog

この方法を用いると、GCP から Secret Key などをダウンロードして GitHub Actions の Secret に登録して環境変数で読み込む..といったことをする必要がなくなります。

正確な情報は他の記事を読むことを推奨しますが、とっつきにくいので噛み砕いて説明すると、 GCP 側で認証が必要な操作を特定のリポジトリのGitHub Actions で予め許可し、要求があったとき(実行時)に有効期限の認証情報を生成して利用する、 という感じのようです。

したがって、Google Cloud側でGitHub ActionsがOIDCを利用して認証できるように設定を行い、このとき発行されたService Account や Workload Identify Providerをセットする作業が必要になります。 そこそこ手順が多く、ちょっとめげそうになりますがなんとか作成できたので解説しながら紹介していきます。

ゴール

GitHub ActionsからGoogle CloudのContainer Registryに対してdocker pushを実現するところまで。 (ほんの少し設定をを変えるだけでArtifactory Registryもいけるはず)

最終的なGitHub Actions

name: Docker Build & Push

on:
release:
types: [created]

jobs:
docker-push:
runs-on: ubuntu-latest

# 必須
permissions:
contents: "read"
id-token: "write"

steps:
- uses: actions/checkout@v3
with:
ref: main
# https://github.com/google-github-actions/auth
- id: "auth"
name: "Authenticate to Google Cloud"
uses: "google-github-actions/auth@v0"
with:
token_format: "access_token"
workload_identity_provider: # ここを発行する
service_account: # ここを発行する
# https://github.com/docker/login-action#google-container-registry-gcr
- name: Login to GCR
uses: docker/login-action@v2
with:
registry: asia.gcr.io
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
- name: "Docker Build & Push"
uses: docker/build-push-action@v3
with:
push: true
tags: gcr.io/your/image:latest

GitHub Actions の Marketplace からは以下の Actions を利用します。 あらゆる手続き的な処理が隠蔽されて設定だけを記述すれば GCP に docker push できる状態になります。

workload_identity_provider と service_account を発行する手順

手順はSetting up Workload Identity Federationに則って実施します。

1. Project を用意する

Google Cloud に Project を用意すると Project ID が発行されるので変数に格納します。

export PROJECT_ID="my-project"

2. Service Account を作成 (Optional)

  • すでに権限が十分な Service Account が存在する場合はスキップして 4 に進んでください。
  • Service Account は存在するが、権限が不十分な場合は 3 に進んでください。
gcloud iam service-accounts create "my-service-account" --project "${PROJECT_ID}"
# Unique IDが自動的に発行されます

3.権限(Permission)の付与 (Optional)

Service Accountは以下から確認できます。

また、すでに Service Account に Role が付与されている場合は、IAM から確認することができます。 Role が存在しない場合は IAM に登場しないため、Role をバインドする必要があります。

3.1 Role の作成

今回、Container Registry に対して Docker Image を Push するので、それに必要なアクセス権を持つ Service Account がすでにあれば、それを利用することも可能です。新規作成や最小構成で作りたい場合は、IAM を使用したアクセス制御  |  Container Registry のドキュメント  |  Google Cloudに従って、Role の作成と Service Account へ権限を付与する必要があります。

必要なアクセス権Role
pull に必要roles/storage.objectViewer
push 及び pull に必要roles/storage.legacyBucketWriter
レジストリホストの追加とバケット作成に必要roles/storage.admin
  1. https://console.cloud.google.com/iam-admin/rolesへ移動
  2. [+ Create Role]をクリック
  3. Title/Description/ID を埋めていく
    • ここでは Title をDocker Push for GitHub Actionsとしておく。
  4. [+Add permissions]を入力
  5. Storage Object ViewerStorage Legacy Bucket WriterStorage Adminをフィルターに追加し残った Permission をすべて追加します。 Add Permission

※ 権限が足りない場合、Access Deniedなど様々なエラーがでるため、混乱することになります。

3.2 Service Account と Role のバインド

[IAM & Admin] > [IAM]へ移動し、ADDから先ほど作成した Service Account と Role を結びつけます

サービスアカウントはメールアドレスのフォーマットで生成されたものを利用します。

4. IAM Credentials AP を有効にする

gcloudコマンドの場合次のコマンドで有効化できます。

gcloud services enable iamcredentials.googleapis.com \
--project "${PROJECT_ID}"

コンソールの画面からだと、[IAM & Admin] > [Workload Identity Federation]に行き、GET STARTEDをクリックすると有効化されます。

5. Workload Identity Pool を作成する

Workload ID Pool は外部サービスとの連携のために利用され、少なくとも 1 つ以上の Provider に接続することが必要です。

# プール名は後から変更できないので注意
gcloud iam workload-identity-pools create "my-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="Demo pool"

6. Workload Identity Pool のフル ID を取得

gcloud iam workload-identity-pools describe "my-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--format="value(name)"

変数に格納

export WORKLOAD_IDENTITY_POOL_ID="..."

7. Workload Identify Pool に対して Provider を作成する

gcloud iam workload-identity-pools providers create-oidc "github-actions-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="github-actions-pool" \
--display-name="GitHub Actions Provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com"

Provider Attributesのマッピングは以下の通り

Google NOIDC N
google.subjectassertion.sub
attribute.actorassertion.actor
attribute.repositoryassertion.repository

8. リポジトリから発信されるワークロードIDプロバイダからの認証が、上記で作成したサービスアカウントになりすますことを許可する。

export REPO="username/name" # 信頼するGitHub Repository (e.g. "google/chrome")

gcloud iam service-accounts add-iam-policy-binding "my-service-account@${PROJECT_ID}.iam.gserviceaccount.com" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"

コンソールでは、以下の手順で実施します。

  1. Workload Identity Federationへ行く
  2. Workload Identify Poolを選択
  3. GRANT ACCESSをクリックして、権限移譲先のService Accountを選択する
  4. Only identities matching the filterを選択すると、先程登録したAttributeのrepositoryを選択
  5. リポジトリ名を登録
  6. DOWNLOAD CONFIGのポップアップが出てくるが不要なのでDISMISS

Service AccountにWorkload Identity UserのRoleが付与されていることが確認できます。

9. Workload Identity Providerのリソース名を抽出する。

gcloud iam workload-identity-pools providers describe "my-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="my-pool" \
--format="value(name)"

10. 完了

以下の2つを利用してGitHub ActionsがらGoogle Cloudの認証を得ることができます。 裏側ではOIDCトークンの交換が行われています。

  • Workload Identity Provider ID
    • projects/$PROJECT_ID/locations/global/workloadIdentityPools/$WORKLOAD_IDENTITY_POOL_ID/providers/$PROVIDER_ID のフォーマット
    • ProviderのEdit画面でhttps://iam.googleapis.com/以降の文字列が同等
  • Service Account email
    • Workload Identity Userの権限とContainer Registryにdocker pushするのに十分な権限を持つService Account

まとめ

最初実施すると手順は厄介ですが、地道に手を動かしてみると必要十分な手順であることがわかります。 認証のためにGitHub Actionsに指定するパラメーターがWorkload Identity Provider IDService Account emailのみになり、シークレットーキーをダウンロードする行為から開放されます。