Open4

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

Kotone/NanoKotone/Nano

小さく始めたほうがいい

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

Kotone/NanoKotone/Nano

鶏(tfstate)と卵(backend)問題

Terraformが生成するtfstateを共有するためにはデータを乗っけるためのインフラ(backend)が必要だが、そのインフラ定義にTerraformが必要という矛盾が生じる。
この問題を解決する方法は大きく4つある:

  1. backendに使うためのリソースを手動で作る
  2. backendに使うためのリソースを他のIaCソリューションで作る(AWS→CodeFormation、GCP→Cloud Deployment manager)
  3. terragruntを使う
  4. Terraform Cloudを使う

手動で作るのが一番わかりやすいけどbackendのリソースを細かく設定したり複製する際に大変(本末転倒)。他のIaCソリューションで作るのは手動より楽だけどTerraform以外のベンダー固有技術を学ぶことになるので手間がかかってしまう。Terragruntは今回は学習対象外なので印象論になるけどいい塩梅にベンダー固有のソリューションに縛られずに解決できそう(実際できるのかはまだわからない)。Terraform Cloudはマネージド・サービスで殴るイメージ、一番便利だし楽だし確実ではありそう。

Kotone/NanoKotone/Nano

↑だと権限が足りない

roles/firebase.developAdminroles/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}",
  ]
}