Open4
FirebaseのインフラリソースをTerraform管理する奮闘記

小さく始めたほうがいい
色々と一気に作ろうとすると何がいけないのかわからなくて詰む。
一番基本のところから作って言って都度plan→applyしていけば簡単にインクリメンタルにできるからいい。

鶏(tfstate)と卵(backend)問題
Terraformが生成するtfstateを共有するためにはデータを乗っけるためのインフラ(backend)が必要だが、そのインフラ定義にTerraformが必要という矛盾が生じる。
この問題を解決する方法は大きく4つある:
- backendに使うためのリソースを手動で作る
- backendに使うためのリソースを他のIaCソリューションで作る(AWS→CodeFormation、GCP→Cloud Deployment manager)
- terragruntを使う
- Terraform Cloudを使う
手動で作るのが一番わかりやすいけどbackendのリソースを細かく設定したり複製する際に大変(本末転倒)。他のIaCソリューションで作るのは手動より楽だけどTerraform以外のベンダー固有技術を学ぶことになるので手間がかかってしまう。Terragruntは今回は学習対象外なので印象論になるけどいい塩梅にベンダー固有のソリューションに縛られずに解決できそう(実際できるのかはまだわからない)。Terraform Cloudはマネージド・サービスで殴るイメージ、一番便利だし楽だし確実ではありそう。

OIDCでGitHub Actions経由でデプロイするまで
Terraformはこちらを参照
GitHub Actionsまわりはこちらを参照

↑だと権限が足りない
roles/firebase.developAdmin
と roles/iam.serviceAccountUser
が必要なのでつける。
# OIDC resources
resource "google_iam_workload_identity_pool" "oidc" {
project = google_project.default.project_id
workload_identity_pool_id = var.gcp_wip_pool_id
description = "OpenID Connection"
display_name = var.gcp_wip_pool_id
timeouts {}
}
resource "google_iam_workload_identity_pool_provider" "github" {
project = google_project.default.project_id
workload_identity_pool_id = google_iam_workload_identity_pool.oidc.workload_identity_pool_id
workload_identity_pool_provider_id = var.gcp_wip_provider_id
display_name = "GitHub Identity Provider"
disabled = false
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
allowed_audiences = []
}
attribute_mapping = {
"google.subject" = "assertion.sub",
"attribute.actor" = "assertion.actor",
"attribute.repository" = "assertion.repository",
}
timeouts {}
}
resource "google_service_account" "github_actions" {
project = google_project.default.project_id
account_id = "github-actions"
display_name = "GitHub Actions"
description = "Access from GitHub Actions"
disabled = false
timeouts {}
}
data "google_iam_policy" "oidc_github_repo" {
binding {
members = [
"principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.oidc.name}/attribute.repository/${var.github_repo_full_name}",
]
role = "roles/iam.workloadIdentityUser"
}
}
resource "google_service_account_iam_policy" "oidc_github_repo" {
service_account_id = google_service_account.github_actions.name
policy_data = data.google_iam_policy.oidc_github_repo.policy_data
}
resource "google_project_iam_binding" "firebase_developAdmin" {
project = google_project.default.project_id
for_each = toset([
"roles/firebase.developAdmin",
"roles/iam.serviceAccountUser",
])
role = each.key
members = [
"serviceAccount:${google_service_account.github_actions.email}",
]
}