🚡

CircleCI から Google Cloud への OIDC を用いた認証

2023/10/07に公開

概要

今日紹介するのは、先日発表された CircleCI の OIDC 対応を用いた Google Cloud への認証方法に関する手法の調査についてです。

https://twitter.com/CircleCIJapan/status/1507524861396422657?s=20&t=p2gpua2mHzXZxrEKDd6GgA

Goal

Google Cloud の Service Account ( 以下、 GSA ) へ Impersonate 出来る CircleCI の Project を制限しつつ、 GSA を利用した Google Cloud への認証を行うことを目的としています。

How to

早速、必要なリソースを作成していきます。

Workload Identity Pool / Provider を作成します

まずは、 Google Cloud に対して OIDC 経由での認証を行うためのサービスである Workload Identity Federation を利用するために Pool と Provider を作成します。
作成にあたって、 CircleCI の Organization ID を local.circleci_org に設定します。

locals {
  circleci_org = "****"
}

resource "google_iam_workload_identity_pool" "circleci" {
  provider                  = google-beta
  workload_identity_pool_id = "circleci"
  display_name              = "circleci"
}

resource "google_iam_workload_identity_pool_provider" "circleci" {
  provider                           = google-beta
  workload_identity_pool_id          = google_iam_workload_identity_pool.circleci.workload_identity_pool_id
  workload_identity_pool_provider_id = "circleci"
  display_name                       = "circleci"
  attribute_mapping = {
    "attribute.project_id" = "assertion['oidc.circleci.com/project-id']" # CircleCI の Project を制限するためにマッピングを行います。
    "google.subject"       = "assertion.sub"
  }
  oidc {
    issuer_uri = "https://oidc.circleci.com/org/${local.circleci_org}" # Issuer URL は CircleCI Organization ごとに発行されます。
    allowed_audiences = [local.circleci_org]
  }
}

GSA を作成します

GSA を作成し、 Impersonate 出来る member に先ほど作成した Workload Identity Pool と、マッピングした CircleCI Project ID を指定しています。
attribute.project_id/*** の部分で CircleCI Project を制限しています。
そして、 google_project_iam_member で該当の GSA に対して必要な権限を付与します。

locals {
  gsa_name = "***"
}

resource "google_service_account" "default" {
  account_id   = local.gsa_name
  display_name = local.gsa_name
}

resource "google_service_account_iam_member" "default" {
  for_each = toset([
    "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.circleci.name}/attribute.project_id/<CircleCI Project ID>",
  ])
  service_account_id = google_service_account.default.id
  role               = "roles/iam.workloadIdentityUser"
  member             = each.value
}

resource "google_project_iam_member" "default" {
  for_each = toset([
    "roles/editor", # 操作したい権限を付与します
  ])
  project = var.project
  role    = each.value
  member  = "serviceAccount:${google_service_account.default.email}"
}

CircleCI Context を作成する

CircleCI の Organization Settings → Contexts より Context を作成します。

CircleCI Config を編集する

CircleCI から GCP に OIDC 認証を行うステップをまとめた CircleCI Orb を作成していますので、そちらを利用していきます。

https://circleci.com/developer/orbs/orb/tetsuya28/gcp-oidc-orb

CircleCI の設定ファイル ( .circleci/config.yaml ) の orbs
に上記の Orb を設定します。また、 jobs.*.steps に以下のステップを追加します。

step の中で Orb の initialize コマンドを呼び出し、 OIDC 認証に必要なパラメータを渡します。 initialize コマンド内で gcloud CLI のインストールと GOOGLE_APPLICATION_CREDENTIALS の設定を行なっています。そのため、 step を実行後は gcloud コマンドを実行するだけで対象の GCP Project に対する操作を行うことが可能になります。

最後に、 .circleci/config.yamlworkflows において OIDC を利用したい job に Context を指定することで全ての設定が完了します。 Context を指定することで OIDC 認証に必要な CIRCLECI_TOKEN 環境変数が CI 上で利用出来るようになります。

At last

CircleCI の OIDC トークンを利用して Google Cloud への認証を行うためにのドキュメントや記事がまだなく、試行錯誤していたので少しでも同じ境遇の人の助けになればと思います。
また、この方法はベストプラクティスではないと思われるため、もっと簡単に出来るよ!などありましたらお気軽にコメントや Twitter でもご連絡お待ちしています。
個人的には Orbs を使ってよしなに認証したかったのですが、正常に動作させることが出来ず…

Others

本日紹介した CircleCI の OIDC 対応ですが、 AWS に対する利用方法は Classmethod さんで詳しい記事が紹介されているので是非ご覧ください。

https://dev.classmethod.jp/articles/circleci-supported-oidc-so-i-tried-linking-it-with-aws/

Discussion