🌩

GitHub Actions で OIDC を使用して GCP 認証を行う

2022/10/19に公開

躓きまくったので備忘録。
AWS はこっち。

https://zenn.dev/kou_pg_0131/articles/gh-actions-oidc-aws

概要

GitHub Actions では OpenID Connect (OIDC) がサポートされています。
OIDC を使用することによりサービスアカウントキーなどを用意することなく GCP 認証を行うことができます。

詳細については下記ページをご参照ください。

https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect

この記事では GitHub Actions で OIDC を使用して GCP 認証を行うまでの手順をまとめます。

リポジトリ

この記事内で使用しているサンプルコードは下記リポジトリで管理しています。

https://github.com/koki-develop/gh-actions-oidc-example

手順

1. IAM Service Account Credentials API を有効にする

OIDC で認証情報を作成するときには IAM Service Account Credentials API を利用するため、有効にしておく必要があります。

Terraform で有効にする場合のサンプルコード
resource "google_project_service" "iamcredentials" {
  service = "iamcredentials.googleapis.com"
}
gcloud CLI を使用する場合のコマンド
gcloud services enable iamcredentials.googleapis.com \
  --project="<プロジェクトID>"

サイドメニューから API とサービスライブラリ の順にクリックして検索画面に遷移します。

検索ボックスに IAM Service Account Credentials API と入力して検索します。

IAM Service Account Credentials API をクリックします。

有効にする をクリックします。
これで IAM Service Account Credentials API が有効になります。

2. サービスアカウントを作成する

GitHub Actions でアクセス権を借用するためのサービスアカウントを作成します。
ついでにここでアクセス権も付与しておきます。

Terraform で作成する場合のサンプルコード
resource "google_service_account" "github_actions" {
  account_id = "<任意のID>"
}

# 任意のロールを付与しておく
# roles/storage.objectViewer を付与する例
resource "google_project_iam_member" "github_actions_storage_object_viewer" {
  project = var.project
  role    = "roles/storage.objectViewer"
  member  = "serviceAccount:${google_service_account.github_actions.email}"
}
gcloud CLI を使用する場合のコマンド
# サービスアカウントを作成
gcloud iam service-accounts create "サービスアカウント名" \
  --project="プロジェクトID"

# 任意のロールを付与しておく
# roles/storage.objectViewer を付与する例
gcloud projects add-iam-policy-binding "<プロジェクトID>" \
  --member="serviceAccount:<サービスアカウントのメールアドレス>" \
  --role="roles/storage.objectViewer"

サイドメニューから IAM と管理サービスアカウント の順にクリックしてサービスアカウント管理画面に遷移します。

サービスアカウントを作成 をクリックします。

サービスアカウント名サービスアカウント ID に任意の値を入力して 完了 をクリックします。
これでサービスアカウントが作成されます。

作成したサービスアカウントにアクセス権を付与します。
IAM と管理 のサイドメニューから IAM をクリックしてアクセス権管理画面に遷移します。

アクセス権を付与 をクリックします。

新しいプリンシパル に先程作成したサービスアカウントのメールアドレスを入力し、任意のロールを割り当てます。
ここでは例として Storage オブジェクト閲覧者 ( roles/storage.objectViewer ) を割り当てておきます。
それぞれ入力できたら 保存 をクリックします。
これでサービスアカウントにアクセス権が付与されます。

3. Workload Identity プール・プロバイダ を作成する

OIDC に使用する Workload Identity プール・プロバイダ を作成します。

Terraform で作成する場合のサンプルコード
resource "google_iam_workload_identity_pool" "github_actions" {
  workload_identity_pool_id = "<任意のID>"
}

resource "google_iam_workload_identity_pool_provider" "github_actions" {
  workload_identity_pool_provider_id = "<任意のID>"
  workload_identity_pool_id          = google_iam_workload_identity_pool.github_actions.workload_identity_pool_id

  oidc {
    issuer_uri = "https://token.actions.githubusercontent.com"
  }

  attribute_mapping = {
    "google.subject"       = "assertion.sub"
    "attribute.repository" = "assertion.repository"
    "attribute.actor"      = "assertion.actor"
  }
}
gcloud CLI を使用する場合のコマンド
# プールを作成
gcloud iam workload-identity-pools create "<任意のID>" \
  --project="<プロジェクトID>" \
  --location="global"

# プロバイダを作成
gcloud iam workload-identity-pools providers create-oidc "<任意のID>" \
  --project="<プロジェクトID>" \
  --location="global" \
  --workload-identity-pool="<プールID>" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.actor=assertion.actor" \
  --issuer-uri="https://token.actions.githubusercontent.com"

サイドメニューから IAM と管理Workload Identity 連携 の順にクリックして Workload Identity プールの管理画面に遷移します。

プールを作成 をクリックします。

名前 に任意のプール名を入力して 続行 をクリックします。

各項目を次のように入力します。

項目
プロバイダの選択 OpenID Connect(OIDC)
プロバイダ名 任意のプロバイダ名。
発行元(URL) https://token.actions.githubusercontent.com
オーディエンス デフォルトのオーディエンス

入力したら 続行 をクリックします。

属性マッピングを次のように設定します。

Google OIDC
google.subject assertion.sub
attribute.repository assertion.repository
attribute.actor assertion.actor

マッピングを設定したら 保存 をクリックします。
これで Workload Identity プールとプロバイダが作成されます。

4. Workload Identity プールからサービスアカウントのアクセス権を借用できるようにする

Terraform で作成する場合のサンプルコード
resource "google_service_account_iam_member" "github_actions_iam_workload_identity_user" {
  service_account_id = google_service_account.github_actions.id
  role               = "roles/iam.workloadIdentityUser"
  member             = "principalSet://iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/<プールID>/attribute.repository/<GitHubユーザー名>/<GitHubリポジトリ名>"
}
gcloud CLI を使用する場合のコマンド
gcloud iam service-accounts add-iam-policy-binding \
  "<サービスアカウントのメールアドレス>" \
  --project="<プロジェクトID>" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/<プールID>/attribute.repository/<GitHubユーザー名>/<GitHubリポジトリ名>"

後ほど必要になるため、「3. Workload Identity プール・プロバイダ」の手順で作成したプールの IAM プリンシパルを取得しておきます。
サイドメニューから IAM と管理Workload Identity 連携 の順にクリックして Workload Identity プールの管理画面に遷移します。

先程作成したプールをクリックして詳細画面に遷移します。

IAM プリンシパル の値を控えておきます。

続いて、 Workload Identity プールからサービスアカウントのアクセス権を借用できるように設定します。
IAM と管理 のサイドメニューから サービスアカウント をクリックしてサービスアカウント管理画面に遷移します。

2. サービスアカウントを作成する」の手順で作成したサービスアカウントをクリックします。

権限 タブをクリックします。

アクセスを許可 をクリックします。

新しいプリンシパル に先程控えておいた Workload Identity プールの IAM プリンシパルを入力し、末尾の /* の部分を /attribute.repository/<GitHubユーザー名>/<GitHubリポジトリ名> のように書き換えてください。

principalSet://iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/<プールID>/*
↓末尾を修正する
principalSet://iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/<プールID>/attribute.repository/<GitHubユーザー名>/<GitHubリポジトリ名>

こうすることで、 OIDC による認証を行うことのできるリポジトリを制限しています。
末尾を /* にすると全ての GitHub リポジトリから認証できるようになってしまうため、必ず制限してください
ロールには Workload Identity ユーザー ( roles/iam.workloadIdentityUser ) を割り当ててください。
それぞれ入力できたら 保存 をクリックします。

5. GitHub Actions で OIDC を使用して GCP 認証を行う

ここまでやってようやくワークフローを作成します。

GCP 認証には google-github-actions/auth アクションを使用します。
サービスアカウントと Workload Identity プールプロバイダの完全修飾識別子を指定するだけで OIDC を使用した GCP 認証を行ってくれます。便利。

下記は GCP 認証を行った後にプライベートな GCS バケットのオブジェクト一覧を取得するワークフローのサンプルです。
permissionsid-token: write を設定しないと OIDC を使えないので注意です。

.github/workflows/main.yml
name: gcp

on:
  push:

jobs:
  gsls:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: google-github-actions/auth@v0
        with:
          workload_identity_provider: 'projects/<プロジェクト番号>/locations/global/workloadIdentityPools/<プールID>/providers/<プロバイダID>'
          service_account: '<サービスアカウントのメールアドレス>'

      # プライベートな GCS バケットを読み取ってみる
      - run: gcloud storage ls gs://oidc-test-bucket-example

GCP リソースにアクセスできています。わーい。

参考

https://github.com/google-github-actions/auth
https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-google-cloud-platform
https://zenn.dev/vvakame/articles/gha-and-gcp-workload-identity

Discussion