Workload Identity連携をしてGitHub ActioinsからCloud Functionsをdeployする

Workload Identity連携とは

何が嬉しいのか

Workload Identity連携 (Workflow Identity Federation)とは、GCPと外部のワークロード(Workload)
とのID連携のことです。
従来はサービスアカウントキーを用いて認証認可を行うことが一般的でしたが、Workflow Identity連携を用いるとサービスアカウントキーを使わずに、GCP外のワークロードからGCPのリソースへアクセス出来るようになります。
サービスアカウントキーを管理する手間が減ることは流出などセキュリティリスクを減らすことに繋がります。

どういう仕組みか

GitHub ActionsからCloud FunctionsにDeployする事例で解説してみます。

  1. WorkloadがIdP(Identity Provider)に認証
  2. IdPがクレデンシャルをWorkloadを経由してGCPのSTS(Security Token Services)に渡す
  3. STSがクレデンシャルを事前登録内容と照合
  4. STSがWorkloadに一時トークンを発行
  5. Workloadが一時トークンを用いてgcloudコマンドを実行

こちらのブログの「リソースアクセスまでの流れ」の解説が参考になりました。
christina04.hatenablog.com


設定の仕方

事前準備

  • GitHub Actionsを動かすためのリポジトリ(hoge)とworkflowファイルを作成
  • Cloud Functionsのコード(main.py)を作成
  • Cloud Functionsを動かすためのサービスアカウントを作成

Workload Identity Poolの設定

「IAM」→「Workload Identity 連携」→「プールを作成」
名前の欄に「test-pool」と入力

IdP (Identity Provider)の登録とWorkload Identity Poolの追加

本説明では、GitHub ActionsからGCPリソースへのアクセスを事例にしているため、GitHubのプロバイダを用います。
下記の値を入力します。*1

プロバイダの選択 Open ID Connect
プロバイダ名 GitHub
プロバイダID github
発行元 https://token.actions.githubusercontent.com 公式ドキュメント参照の値
オーディエンス デフォルトのオーディエンス

プロバイダの属性設定では、下記の値を入力します。

属性マッピング google.subject = assertion.repository
属性条件 assertion.repository == "GitHub組織名/リポジトリ名" (gesogse0/hoge)

外部IDがサービスアカウントを使えるようにする

作成したWorkload Identittyプールの画面を開き「アクセスを許可」を開きます。
「サービスアカウント」には利用したいサービスアカウントを、
「プリンシパル」には「フィルタに一致するIDのみ」を選択し、「subject」を選択し、入力欄には「リポジトリ所有者/リポジトリ名(gesoges0/hoge)」を入力します。

ここまで登録すると、下記コマンドで外部IDに権限が付与されていることが伺えます。

gcloud iam service-accounts get-iam-policy <サービスアカウント>

workflowにdeploy jobを記述する

まず下記のコマンドでprovider_idを取得します。

gcloud iam workload-identity-pools providers describe "github"   --project=$PROJECT_ID   --location="global"   --workload-identity-pool="test-pool"   --format='value(name)'

provider_idが取得できたら下記のworkflowを記述します。
これで、mainリポジトリにpushしたらmain.pyのhello_http()関数をCloud FunctionsにDeployできるようになります。

name: Deploy Cloud Functions
on:
  # 手動ormainブランチにpush時に実行
  workflow_dispatch:
  push:
    branches:
      - main

jobs:
  deploy-job:
    runs-on: 'ubuntu-latest'
    permissions:
      contents: 'read'
      id-token: 'write'

    steps:
      # ソースコードのチェックアウトをする
    - uses: 'actions/checkout@v3'

    - id: 'auth'
      name: 'Authenticate to Google Cloud'
      # Workload Identity連携を利用してGitHub ActionsからGoogle Cloudへ認証を行う
      uses: 'google-github-actions/auth@v1'
      with:
        workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER_ID }}
        service_account: ${{ vars.SERVICE_ACCOUNT }}

    - name: 'Set up Cloud SDK'
      # gcloudコマンドを実行するためにCloud SDKを準備する
      uses: 'google-github-actions/setup-gcloud@v1'

    - name: 'Deploy Cloud Functions gen2 Using gcloud command'
      # gcloudコマンドを利用してCloud Functionsをデプロイする
      run: >-
        gcloud functions deploy ${{ vars.CLOUD_FUNCTIONS_ID }}
        --gen2
        --runtime=python310
        --region=asia-northeast1
        --source=./functions
        --entry-point=hello_http
        --trigger-http
        --no-allow-unauthenticated
        --set-env-vars GCP_PROJECT=${{ vars.PROJECT_ID }}
        --run-service-account ${{ vars.SERVICE_ACCOUNT }}

追記

なお、Cloud Buildでも同じようなことを実現可能です。
下記の手順で実行します。

  1. Cloud Buildコンソールにリポジトリを登録
  2. Cloud Buildでトリガーを作成し、「mainブランチにpushされた場合にトリガーする」ように設定
  3. リポジトリにcloudbuild.yamlを入れ、Cloud FunctionsにDeployするよう記述