Cloud Run から Cloud SQL へのコネクションを作るには Service Account によって承認を通す必要がある。Cloud Function と同じアプローチ。
https://cloud.google.com/sql/docs/mysql/connect-run?hl=ja
前例の記事などがなかったので雰囲気で手を動かしてたらがっつりハマったので備忘録を残していく。
Service Account を作る
Terrafrom で Service Account のリソースを作ると以下のような感じ。
resource "google_service_account" "sa" {
account_id = "my-sa"
display_name = "my-sa"
}
Croud Run側のリソース定義での Service Account 参照。今回作成する Cloud Run はフルマネージド。
resource "google_cloud_run_service" "cloud-run" {
name = my-cloud-run
location = "us-central1"
template {
spec {
containers {
image = "gcr.io/my-project/image-name"
}
// Ref: service account resource
service_account_name = google_service_account.main.email
}
metadata {
annotations = {
"autoscaling.knative.dev/maxScale" = "1000"
// Ref: database instance resource
"run.googleapis.com/cloudsql-instances" = google_sql_database_instance.main.connection_name
"run.googleapis.com/client-name" = "cloud-console"
}
}
}
traffic {
percent = 100
latest_revision = true
}
}
resource "google_sql_database_instance" "my-instance" {
name = "my-instance"
database_version = "MYSQL_5_7"
region = "us-central1"
settings {
tier = D0
}
}
Role のバインドを試行錯誤するもハマる
検証1
data "google_iam_policy"
で作成したポリシーを resource "google_cloud_run_service_iam_policy"
へ適用する作戦で試みてみる。
Cloud Run サービスを一般公開するポリシーの設定についてドキュメントに記載があったのでそちらを参考に見様見真似してみた。
https://www.terraform.io/docs/providers/google/r/cloud_run_service.html#example-usage-cloud-run-service-noauth
実際のコードは以下の通り。
data "google_iam_policy" "my-policy" {
binding {
role = "roles/cloudsql.client"
members = [
"serviceAccount:${google_service_account.main.email}",
]
}
}
resource "google_cloud_run_service_iam_policy" "my-policy" {
location = google_cloud_run_service.cloud-run.location
project = google_cloud_run_service.cloud-run.project
service = google_cloud_run_service.cloud-run.name
policy_data = data.google_iam_policy.my-policy.policy_data
}
resource "google_cloud_run_service_iam_member" "my-policy" {
location = google_cloud_run_service.meshi-log.location
service = google_cloud_run_service.meshi-log.name
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.main.email}"
}
これは エラーになる。
Error: Error setting IAM policy for cloudrun service "v1/projects/my-project/locations/us-central1/services/my-sa": googleapi: Error 400: Role roles/cloudsql.client is not supported for this resource.
Cloud Run の IAM Policy において Roles/cloudsql.client
の Role はサポートしていないということである。
当然 Cloud SQL へのコネクションは貼れていないため Stack Driver を確認すると下記のようなエラーログが出力される。
dial unix /cloudsql/my-project:us-central1:my-instance: connect: connection refused
CloudSQL connection failed. Please see https://cloud.google.com/functions/docs/sql#troubleshooting for additional details: ensure that the account has access to "my-project:us-central1:my-instance" (and make sure there's no typo in that name). Error during createEphemeral for my-project:us-central1:my-instance: googleapi: Error 403: The client is not authorized to make this request., notAuthorized
検証2
Terraform のドキュメントを眺めていて resource "google_service_account_iam_binding"
なるものを見つけた。
これでは?
resource "google_service_account_iam_member"
を使えば 特定の Service Account に対して Policy の定義とバインドを同時にできるみたいなのでそちらを使うことに。
resource "google_service_account_iam_member" "sql" {
service_account_id = google_service_account.sa.name
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.sa.email}"
}
これもダメなのか...。
Error: Error applying IAM policy for service account 'projects/my-project/serviceAccounts/my-sa@my-project.iam.gserviceaccount.com': Error setting IAM policy for service account 'projects/my-project/serviceAccounts/my-sa@my-project.iam.gserviceaccount.com': googleapi: Error 400: Role roles/cloudsql.client is not supported for this resource., badRequest
答え: google_project_iam_binding, google_project_iam_member を使え
terraform-provider-google のリポジトリに同事象のISSUEを発掘した。
https://github.com/terraform-providers/terraform-provider-google/issues/1225
In your case, you should be looking at the google_project_iam_binding resource- similar to how your gcloud command was gcloud projects add-iam-policy-binding. The google_service_account_iam_binding resource corresponds to this gcloud command.
特定のプロジェクトに Service Account を追加、および Role のバインドの操作を gcloud
コマンドから行う場合は gcloud project
コマンドを使うので、Terraform での操作もそれに沿う必要があるのだと解釈した。
resource "google_project_iam_member" "cloud_sql_connection" {
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.sa.email}"
}
これで Cloud Run が roles/cloudsql.client
の Role がバインドされた Service Account を利用して Cloud SQL とコネクションできるようになった。
同じ罠に引っかかる人結構いるのでは?
参考にした記事とか
- https://www.sethvargo.com/configuring-cloud-run-with-terraform/
- https://blog.ri52dksla.dev/posts/gcp-terraform-cloud-run-and-gcs/
- https://cloud.google.com/sql/docs/mysql/connect-run?hl=ja
- https://www.terraform.io/
- https://github.com/terraform-providers/terraform-provider-google/issues/1225
最後に
Cloud Run いいかんじ。