GitHub ActionsなどCI/CD環境からfirebaseのデプロイをするために、認証トークンではなく、サービスアカウントを使うとした時に、GCP Consoleでぽちぽちするのも面倒だなということで、Terraformで作ってみました。
ざっと探してもそのままな例も見つからなかったので、こちらに残しておきます。
サービスアカウント
サービスアカウントは、google_service_account
で作れるので、firebaseのプロジェクトID、accountId(メアド形式のユーザ名部分に相当)、(必要に応じて)アカウントの表示名を指定しておきます。
resource "google_service_account" "service_account" {
project = var.project_id
account_id = "deploy"
display_name = "Deploy user"
}
権限の付与
この辺りは、いろいろ先人の知恵もありgoogle_project_iam_member
を使うのが良いらしいということで、あとは必要な権限を見繕って付与していきます。
Hostingのみを使う場合と、HostingとFunctionsの双方を使う場合の例を示します。
Hostingのみ
resource "google_project_iam_member" "service_account_user" {
project = var.project_id
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "apikeys_viewer" {
project = var.project_id
role = "roles/serviceusage.apiKeysViewer"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "firebaserules_system" {
project = var.project_id
role = "roles/firebaserules.system"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "firebasehosting_admin" {
project = var.project_id
role = "roles/firebasehosting.admin"
member = "serviceAccount:${google_service_account.service_account.email}"
}
Hosting + Functions
Hostingに加えて、roles/cloudfunctions.developer
とroles/secretmanager.viewer
(SecretManagerを使う場合)を指定します。
resource "google_project_iam_member" "service_account_user" {
project = var.project_id
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "apikeys_viewer" {
project = var.project_id
role = "roles/serviceusage.apiKeysViewer"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "firebaserules_system" {
project = var.project_id
role = "roles/firebaserules.system"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "firebasehosting_admin" {
project = var.project_id
role = "roles/firebasehosting.admin"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "cloudfunctions_developer" {
project = var.project_id
role = "roles/cloudfunctions.developer"
member = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_project_iam_member" "secretmanager_viewer" {
project = var.project_id
role = "roles/secretmanager.viewer"
member = "serviceAccount:${google_service_account.service_account.email}"
}
キーの保存
GitHub ActionsのSecretsにキーを保存することを考えてローカルファイルに落としておきます。ローカルに落とさずに、github providerのgithub_actions_secretに渡して一気に登録までしちゃうのが楽でいいですね。
resource "google_service_account_key" "deployuser-key" {
service_account_id = google_service_account.service_account.name
}
resource "local_file" "deployuser-key" {
filename = "./output/secrets/deployuser-key"
content = google_service_account_key.deployuser-key.private_key
file_permission = "0600"
directory_permission = "0755"
}
実際にはtfstateに生でキーが残っちゃうのがちょっとキモい(というかかなりキモい)。なので、OIDCで接続するようにしよう。そうしよう。