😊
GitHub ActionsでのTerraformのPlanとApplyで異なるサービスアカウントを使用する
What
GitHub ActionsでTerraformのCI/CDを構成すると、Terraform PlanはPRのOpen時に、Terraform ApplyはPRのMerge時に発火するようにすることが多いと思います。
この時にTerraformのPlanとApplyで同じサービスアカウントを使用すると、任意のブランチから強力な権限を使用でき、リスクを孕んだ構成となってしまいます。
そのため、TerraformのPlan時には読み取り権限のみ付与したサービスアカウントを使用し、TerraformのApply時のみ更新権限を付与したサービスアカウントを使用するのが望ましいと言えます。
GCPのWorkload Identityを使用して、GitHub ActionsでTerraformのPlanとApplyで異なるサービスアカウントを使用する方法を書きます。
Workload Identity Poolの作成
resource "google_iam_workload_identity_pool" "github_actions" {
project = var.project_id
workload_identity_pool_id = "gh-oidc-pool"
display_name = "GitHub Actions OIDC Pool"
description = "Workload Identity Pool for GitHub Actions"
}
- GitHub Actions用のWorkload Identity Poolを作成します
Workload Identity Pool Providerの設定
resource "google_iam_workload_identity_pool_provider" "github_actions" {
project = var.project_id
workload_identity_pool_id = google_iam_workload_identity_pool.github_actions.workload_identity_pool_id
workload_identity_pool_provider_id = "github-actions"
display_name = "GitHub Actions Provider"
description = "OIDC identity pool provider for GitHub Actions"
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.repository" = "assertion.repository"
"attribute.ref" = "assertion.ref"
"attribute.full_ref" = "assertion.repository + \"/\" + assertion.ref"
}
attribute_condition = "attribute.repository.startsWith(\"${var.github_organization}/\")"
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
}
}
-
attribute_mapping
でGitHubからの情報をGCPの属性にマッピングします -
attribute.full_ref
でリポジトリとブランチの条件を結合したattributeをマッピングします- これにより特定のリポジトリの特定のブランチからの接続を条件として書けるようにしています
-
attribute_condition
で特定のOrganizationのリポジトリからの接続のみを許可しています
Plan用サービスアカウントの設定
resource "google_service_account" "github_actions_plan" {
project = var.project_id
account_id = "github-actions-plan"
display_name = "Service account for GitHub Actions Plan"
}
resource "google_service_account_iam_member" "github_actions_plan" {
service_account_id = google_service_account.github_actions_plan.name
role = "roles/iam.workloadIdentityUser"
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github_actions.name}/attribute.repository/${var.github_organization}/${var.github_repository}"
}
- Plan用のサービスアカウントを作成し、Workload Identity Poolと紐付けます
- 別途
roles/viewer
などの読み取り権限のみを付与するようにします -
attribute.repository
をプリンシパルとしているので、どのブランチからでもPlan用のサービスアカウントを使用できます
Apply用サービスアカウントの設定
resource "google_service_account" "github_actions_apply" {
project = var.project_id
account_id = "github-actions-apply"
display_name = "Service account for GitHub Actions Apply"
}
resource "google_service_account_iam_member" "github_actions_apply" {
service_account_id = google_service_account.github_actions_apply.name
role = "roles/iam.workloadIdentityUser"
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github_actions.name}/attribute.full_ref/${var.github_organization}/${var.github_repository}/refs/heads/main"
}
- Apply用のサービスアカウントを作成し、Workload Identity Poolと紐付けています
- 別途
roles/owner
などの更新権限のみを付与するようにします -
attribute.full_ref
をプリンシパルとしており、main(レビュー済みのコード)からしかApply用のサービスアカウントを使用できないようにしています
Discussion