Google Cloud の Workload Identity を使用して,Github Actions から認証できるように設定します.
- Workload Identity とは
- Workload Identity を設定する
- サービスアカウントとして認証する
- 監査ログを使用する
- 許可する範囲を制限する
- Terraform で管理する
- 参考文献
Workload Identity とは
Workload Identity allows your workloads to access Google Cloud without Service Account keys. There are 4 steps to setting up a workload identity.
- Create a workload identity pool: The pool organizes and manages external identities. IAM lets you grant access to identities in the pool.
- Connect an identity provider: Add either AWS or OpenID Connect (OIDC) providers to your pool.
- Configure provider mapping: Set attributes and claims from providers to show up in IAM.
- Grant access: Use a service account to allow pool identities to access resources in Google Cloud.
Workload Identity により,サービスアカウントの鍵を使わずに,作業プログラムが Google Cloud にアクセスできるようになります.以下の4段階で workload identity を設定します.
- workload identity pool を作成します.これは外部のアイデンティティを整理し管理します.IAM で pool のアイデンティティにアクセスを許可しましょう.
- identity provider に接続します.具体的には,pool に AWS か OpenID Connect (OIDC) provider を追加します.
- provider mapping を設定し,providerからの属性や要求が IAM に表示されるようにします.
- アクセスを許可し,サービスアカウントを使用して,pool に含まれるアイデンティティで Google Cloud のリソースにアクセスします.
https://console.cloud.google.com/iam-admin/workload-identity-pools (拙訳 みー)
Workload Identity を設定する
プロジェクトを開いて,"IAM & Admin" > "Workload Identity Federation" を開き,pool を作成します (step 1).名前は sample (任意)とします.
provider は OIDC (固定) ,名前は my-provider (任意),issuer は "https://token.actions.githubusercontent.com" (固定) ,最初なのでdefault audience に設定します (step 2).
provider attributes は最低限 subject のみ設定すればよいです (step 3).
作成が完了しました.IAM principal が,principalSet://iam.googleapis.com/projects/5xxxxx12/locations/global/workloadIdentityPools/sample/*
となります.
次にサービスアカウントにアクセスを許可します (step 4).別の画面で logger という名前のサービスアカウントを作成し,logs writer を付与しておきましたので,このサービスアカウントを使用します.
接続が完了しました.
Google Cloud で初回に必要な設定は以上です.
サービスアカウントとして認証する
Github Actions を以下のように設定します.
.github/workflows/oidc.yml
name: CI on: [push] permissions: contents: read id-token: write jobs: main: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - id: auth uses: google-github-actions/auth@v1 with: workload_identity_provider: "projects/5xxxxx12/locations/global/workloadIdentityPools/sample/providers/my-provider" service_account: "logger@xxxxxxxx.iam.gserviceaccount.com" - uses: google-github-actions/setup-gcloud@v1 - run: | gcloud logging write github-actions '{"message": "success"}' --payload-type=json
実行すると以下のようにログが出力されました.
一見すると,.github/workflows/oidc.yml
には一切機密情報が含まれていないのに認証ができており,素晴らしいように見えますが,workload_identity_provider
と service_account
の値が漏洩すると,別の Github アカウントの Github Actions でも認証できてしまうので問題です.
監査ログを使用する
IAM can generate audit logs when principals exchange a token. To receive audit logs for all steps of the token-exchange process, you must enable audit logs for Data Access activity for the following APIs:
- Identity and Access Management (IAM) API (enable log type "Admin Read")
- Security Token Service API (enable log type "Admin Read")
After you enable audit logs for Data Access activity, IAM generates an audit log entry each time a principal exchanges a token. The log entry includes the following fields:
- protoPayload.authenticationInfo.principalSubject: The subject of the identity provider token.
For other OIDC identity providers, this field contains the value of the sub, or subject, claim from the OIDC token.
https://cloud.google.com/iam/docs/audit-logging/examples-workload-identity
上記に従って以下のように設定します.
https://console.cloud.google.com/iam-admin/audit
先程の Github Actions を再実行したところ,以下のような監査ログが生成されました.
{ "protoPayload": { "@type": "type.googleapis.com/google.cloud.audit.AuditLog", "status": {}, "authenticationInfo": { "principalSubject": "repo:xxxxxx/xxxxxxx:ref:refs/heads/master" }, "severity": "INFO", "logName": "projects/xxxxxxxx/logs/cloudaudit.googleapis.com%2Fdata_access", ... }
principalSubject
の値が,GitHub のヘルプに記載されている,"repo:
この設定により,誰かが Github Actions 上で勝手に認証を得ようとしたら,その情報がログに残ります.
許可する範囲を制限する
現在の設定では,workload_identity_provider
と service_account
の値を知っている Github Actions 上のジョブならば,認証が成功してしまいます.相手である Google Cloud で制限が必要です.Github Actions は以下のようなフィールドを Google Cloud に提供するので,この値が適切な場合のみ許可をするべきです.
例えば,repository
が特定の値である場合のみ許可するならば以下のように設定します.
全く同じ Github Actions スクリプトを2個のレポジトリに作成し,片方のレポジトリのみ許可する設定にして実行したところ,以下のように許可したレポジトリでは成功し,もう片方のレポジトリではエラーとなりました.
これで,実行するレポジトリを適切に制限できました.
Terraform で管理する
例えば以下のような構成が可能です.
provider "google" { project = var.project_id } variable "project_id" { type = string } variable "repository" { type = string } resource "google_iam_workload_identity_pool" "main" { project = var.project_id workload_identity_pool_id = "main" display_name = "Main Pool" description = "Main Pool" disabled = false } resource "google_iam_workload_identity_pool_provider" "main" { project = var.project_id workload_identity_pool_id = google_iam_workload_identity_pool.main.workload_identity_pool_id workload_identity_pool_provider_id = "main" display_name = "Main Provider" description = "Main Provider" attribute_condition = "assertion.repository==\"${var.repository}\"" attribute_mapping = { "google.subject" = "assertion.sub" "attribute.repository" = "assertion.repository" } oidc { issuer_uri = "https://token.actions.githubusercontent.com" } } resource "google_service_account" "logger" { account_id = "logger" display_name = "A service account for logging" } resource "google_project_iam_binding" "oidc" { project = var.project_id role = "roles/logging.logWriter" members = [ "serviceAccount:${google_service_account.logger.email}" ] } resource "google_service_account_iam_binding" "oidc" { service_account_id = google_service_account.logger.name role = "roles/iam.workloadIdentityUser" members = [ "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.main.name}/attribute.repository/${var.repository}" ] }