サービスアカウントキーを用いずにGitHub ActionsからGoogle Cloudと認証する
本エントリはクラスメソッド Google Cloud Advent Calendar 2021の23日目の記事です。
GitHub Actionsでgcloudコマンドラインツールなどを使ってGoogle Cloudのリソースに対してなにか操作したりしたいことってありますよね。そのためにはGoogle Cloudと認証に利用するサービスアカウントキーの管理をどうするかという問題がでてきます。そこで、今回はサービスアカウントキーを使わず、Workload Identity連携を使って認証し、サービスアカウント情報をgcloudで取得するというGitHub Actionsのワークフローを試してみます。
はじめに
本エントリではGoogle CloudのIAM(Identity and Access Management)のプリンシパル、ロール、ポリシーといったベースとなる概念を理解していることを前提としています。IAMの諸概念についてはこのドキュメントが詳しいのでおすすめです。
Workload Identity連携とは
Workload Identity連携は文字通り、Google Cloudと外部のワークロード(workload)とのID連携です。この機能を使うことで、サービスアカウントキーを使わずに、オンプレや他のクラウドサービスのワークロードからGoogle Cloudのリソースへのアクセスを可能にできます。今回はこのWorkload Identity連携を使って、GitHubのリポジトリにGoogle Cloudリソースへのアクセス権を付与して、サービスアカウントキーなしでの認証を試します。
google-github-actions/authとは
google-github-actions/auth
はGoogle Cloudとの認証時に使うアクションです。使える認証方法はサービスアカウントキーを使ったものと、Workload Identity連携を使ったものの二種類があります。今回はこのアクションを使ったWorkload Identity連携での認証方法を試します。
やってみる
サービスアカウントを作成し、プロバイダの作成などWorkload Identity連携に必要な設定を行います。その後、GitHub ActionsでWorkload Identity連携を用いて認証し、gcloudを使ってサービスアカウントの情報を取得するというワークフローを作成します。
Workload Identity連携の準備
authアクションのドキュメントに記載されている手順に沿って、Workload Identity連携の準備を進めます。
gcloudを使うため、事前準備としてCloud SDKのインストールが必要です。手順についてはドキュメントを参照してください。
まずは環境変数にプロジェクトIDと作成するサービスアカウントの名前を設定します。
export PROJECT_ID="my-project" export SERVICE_ACCOUNT_NAME="my-service-account"
次にGitHub Actions上で利用するサービスアカウントを作成します。
gcloud iam service-accounts create "${SERVICE_ACCOUNT_NAME}" \ --project "${PROJECT_ID}"
サービスアカウントには実行する処理に応じて権限を付与する必要があります。今回はサービスアカウント情報の取得のみを実行するので、iam.serviceAccounts.get
とその他いくつかの権限のみが含まれる事前定義ロールService Account Userを紐付けます。
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --role="roles/iam.serviceAccountUser" \ --member="serviceAccount:${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
次にサービスアカウントの一時的な認証情報を作成できるようにするために、IAM Service Account Credentials APIを有効化します。
gcloud services enable iamcredentials.googleapis.com \ --project "${PROJECT_ID}"
Workload Identityプールを作成します。Workload Identityプールは外部IDとGoogle Cloudとの紐付けを設定したWorkload Identityプロバイダをグループ化し、管理するためのもののようです。
gcloud iam workload-identity-pools create "my-pool" \ --project="${PROJECT_ID}" \ --location="global" \ --display-name="Demo pool"
Workload IdentityプールのIDを取得します。
gcloud iam workload-identity-pools describe "my-pool" \ --project="${PROJECT_ID}" \ --location="global" \ --format="value(name)"
取得したIDを環境変数に設定します。
export WORKLOAD_IDENTITY_POOL_ID="..."
先ほど作成したWorkload Identityプールの中にWorkload Identityプロバイダを作成します。
gcloud iam workload-identity-pools providers create-oidc "my-provider" \ --project="${PROJECT_ID}" \ --location="global" \ --workload-identity-pool="my-pool" \ --display-name="Demo provider" \ --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \ --issuer-uri="https://token.actions.githubusercontent.com"
--attribute-mappingにはGitHub ActionsのJWTからGoogle Cloudのattributeへのマッピングを設定します。IAMポリシーの設定等で利用する値についてはマッピングしておく必要があります。今回はsubとactor、repositoryをマッピングしています。JWTの内容についてはGitHubのドキュメントに記載されています。
今回は設定しませんが、--attribute-conditionを使うことで、JWTの値やマッピング後の値などをもとに認証するプロバイダの条件を設定することも可能です。
次に環境変数のREPO
にGitHub Actionsを動かすリポジトリを設定し、IAMポリシーバインディングを作成します。このIAMポリシーバインディングでは、member
が指定したサービスアカウント(SERVICE_ACCOUNT_NAME)を利用できるようにするものです。role
ではサービスアカウントのアクセストークンなどを取得するための権限がついたロールを指定しています。
export REPO="username/name" gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \ --project="${PROJECT_ID}" \ --role="roles/iam.workloadIdentityUser" \ --member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
GitHub Actionsのワークフローで利用するため、Workload Identityプロバイダの名前を取得しておきます。
gcloud iam workload-identity-pools providers describe "my-provider" \ --project="${PROJECT_ID}" \ --location="global" \ --workload-identity-pool="my-pool" \ --format='value(name)'
これで準備は完了です。
今回はgcloudを使って設定しましたが、Terraformを使った例も公開されています。
GitHub Actionsのワークフローを作成する
先程作成したサービスアカウントでWorkload Identity連携を用いて認証し、google-github-actions/setup-gcloudを使ってgcloudをインストールして、サービスアカウント情報の取得を試してみます。使用するワークフローの定義は次のとおりです。このワークフロー.github/workflows/runGcloud.yaml
に保存し、mainブランチにpushします。
name: runGcloud on: workflow_dispatch: jobs: run: runs-on: ubuntu-latest permissions: id-token: 'write' steps: - id: auth uses: google-github-actions/auth@v0 with: workload_identity_provider: '{プロバイダ名}' service_account: 'my-service-account@{プロジェクトID}.iam.gserviceaccount.com' - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@v0 - name: Describe my-service-account run: gcloud iam service-accounts describe 'my-service-account@{プロジェクトID}.iam.gserviceaccount.com'
Workflow Identity連携をする上での注意点としては、permissionsにid-token: 'write'
を追加する必要があります。そのため、もともとpermissionsを指定してなかった場合にはデフォルトの権限が上書きされるため、必要に応じて権限の追加が必要です。設定可能な権限やデフォルトの権限についてはドキュメントを参照してください。
今回利用したアクションsetup-gcloud
やauth
で指定できる引数については各ドキュメントを参照してください。
ワークフローを実行する
mainブランチにpushされることで、ワークフロー一覧に該当ワークフローが出てくるため、手動実行します。手動実行すると、数秒から数十秒程度で完了します。各ステップの出力を見てみます。
google-github-actions/auth
の実行結果は次の通りです。明示的に指定していない引数のデフォルト値も表示されているのと、認証情報がファイルに書き込まれている事がわかります。ちなみにサービスアカウントにバインドする際にmember
に指定したリポジトリと異なるリポジトリで実行したり、存在しないサービスアカウントを指定したとしてもここではエラーにはならなかったです。
Run google-github-actions/auth@v0 with: workload_identity_provider: projects/{プロジェクト番号}/locations/global/workloadIdentityPools/my-pool/providers/my-provider service_account: my-service-account@{プロジェクトID}.iam.gserviceaccount.com create_credentials_file: true cleanup_credentials: true access_token_lifetime: 3600s access_token_scopes: https://www.googleapis.com/auth/cloud-platform id_token_include_email: false Created credentials file at "/home/runner/work/google-cloud-auth-sample/google-cloud-auth-sample/a1826994e98236817215a7df"
続いて、google-github-actions/setup-gcloud
の実行結果です。引数のデフォルト値や環境変数とアクション内で実行されたであろうtar
のコマンドが表示されてますね。
Run google-github-actions/setup-gcloud@v0 with: version: latest export_default_credentials: false cleanup_credentials: true env: CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE: /home/runner/work/google-cloud-auth-sample/google-cloud-auth-sample/d8a676702f60a47af6097152 GOOGLE_APPLICATION_CREDENTIALS: /home/runner/work/google-cloud-auth-sample/google-cloud-auth-sample/d8a676702f60a47af6097152 GOOGLE_GHA_CREDS_PATH: /home/runner/work/google-cloud-auth-sample/google-cloud-auth-sample/d8a676702f60a47af6097152 CLOUDSDK_PROJECT: {プロジェクトID} CLOUDSDK_CORE_PROJECT: {プロジェクトID} GCP_PROJECT: {プロジェクトID} GCLOUD_PROJECT: {プロジェクトID} GOOGLE_CLOUD_PROJECT: {プロジェクトID} /usr/bin/tar xz --warning=no-unknown-keyword --overwrite -C /home/runner/work/_temp/aba23c62-f7c9-49bc-8368-997d52c6fcba -f /home/runner/work/_temp/da334eea-9720-4b23-b24c-a79c30e7143c
最後に、gcloudを使ったサービスアカウント情報の取得結果です。環境変数とともに、実行結果としてアカウント情報が表示されました。無事サービスアカウントの認証ができていそうです。
Run gcloud iam service-accounts describe 'my-service-account@{プロジェクトID}.iam.gserviceaccount.com' gcloud iam service-accounts describe 'my-service-account@{プロジェクトID}.iam.gserviceaccount.com' shell: /usr/bin/bash -e {0} env: CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE: /home/runner/work/google-cloud-auth-sample/google-cloud-auth-sample/d8a676702f60a47af6097152 GOOGLE_APPLICATION_CREDENTIALS: /home/runner/work/google-cloud-auth-sample/google-cloud-auth-sample/d8a676702f60a47af6097152 GOOGLE_GHA_CREDS_PATH: /home/runner/work/google-cloud-auth-sample/google-cloud-auth-sample/d8a676702f60a47af6097152 CLOUDSDK_PROJECT: {プロジェクトID} CLOUDSDK_CORE_PROJECT: {プロジェクトID} GCP_PROJECT: {プロジェクトID} GCLOUD_PROJECT: {プロジェクトID} GOOGLE_CLOUD_PROJECT: {プロジェクトID} CLOUDSDK_METRICS_ENVIRONMENT: github-actions-setup-gcloud email: my-service-account@{プロジェクトID}.iam.gserviceaccount.com etag: MDEwMjE5MjA= name: projects/{プロジェクトID}/serviceAccounts/my-service-account@{プロジェクトID}.iam.gserviceaccount.com oauth2ClientId: {クライアントID} projectId: {プロジェクトID} uniqueId: {クライアントID}
さいごに
今回はGitHub ActionsのワークフローからWorkload Identity連携での認証を試してみました。予め専用の設定が必要にはなりますが、キーの扱いが不要なので総合的に見るとかなり便利だと思います。一方でアクセス権を付与してしまうとキー無しでの認証が可能になるので、アクセス権の付与先には注意が必要です。サービスアカウントの紐付ける対象のリポジトリやユーザー名(もしくはorganization)は確認が必要です。必要に応じてWorkflow Identityプロバイダの属性条件で制限しておくのも良いと思います。また、今回はGitHub Actionsでgcloudを使うためにgoogle-github-actions/setup-gcloudを使いましたが、google-github-actions/deploy-cloudrunのようにCloud Runのデプロイなど特定の機能に特化したアクションもあります。Google GitHub Actionsから目的に応じた必要なアクションを探してみると良さそうです。