Cloud RunからCloud SQLへIAM データベース認証で接続する
この記事は モニクル Advent Calendar 2024 16 日目の記事です。
15 日目は Excel で VBA を使わないでドラクエ 3 のパズルを作ってみた でした。VBA を使わずに Excel でゲームを作るシリーズ、とても面白いのでぜひ読んでみてください。
はじめに
Cloud SQL に接続する際にみなさんはどのような方法で接続していますか?
筆者は最近までユーザー名とパスワードで接続する方法(組み込みデータベース認証[1])しか知りませんでした。
Terraform でユーザーを作る場合、tfstate にパスワードが載ってしまうため秘匿情報をどうしようかと工夫せねばなりませんし、そもそもユーザーは Terraform で管理しないという選択をすることもあるかと思います。最近の Terraform のアップデートでは ephemeral values
が追加になりましたし、この方法で管理する手もあるでしょう。
しかしながら、データベース接続に IAM の認証情報を利用して接続する方法(IAM データベース認証[2])を選択すればこのような管理から解放されるため、筆者としてはこの方法に寄せていきたいなと考えました。
どうするか?
同僚の asuka が書いた記事が詳しいです。Go, Java, Python, or Node.js であれば公式から提供されている Connector をアプリケーションで利用して IAM データベース認証で接続ができるよというものです。
著者は諸事情により異なるアプローチで試してみました。Cloud Run のサイドカーコンテナで Cloud SQL Auth Proxy[3] を利用して自動認証する方法です。
方法
筆者は Terraform をよく使いますので Terraform のコードで紹介します。使わない場合は適宜読み替えていただき Cloud Console でお試しください。
前提条件として以下とさせてください。
-
cloudsql.iam_authentication
フラグが on となっている Cloud SQL のインスタンスはセットアップ済み - Cloud SQL に接続したいアプリケーションをデプロイする Cloud Run が利用するサービスアカウントに
roles/run.invoker
(またはそれ相当) のロールは付与済み - Cloud Run は Direct VPC Egress[4] を利用して VPC にトラフィックを送信する
1. Cloud Run が利用するサービスアカウントが Cloud SQL に接続できるようにする
Cloud SQL のインスタンスに IAM データベース認証で接続できるユーザーを作成します。
接続に必要となるロールをサービスアカウントに付与します。
# データベースのユーザーを作成
resource "google_sql_user" "db_user" {
project = "<プロジェクトID>"
name = "<Cloud Runが利用するサービスアカウントemailの末尾.gserviceaccount.comを取り除いたもの>"
instance = "<Cloud SQLのインスタンス名>"
type = "CLOUD_IAM_SERVICE_ACCOUNT"
}
# ロールを付与
resource "google_project_iam_member" "db_user_client_role" {
project = "<プロジェクトID>"
role = "roles/cloudsql.client"
member = "serviceAccount:<Cloud Runが利用するサービスアカウントemail>"
depends_on = [google_sql_user.db_user]
}
resource "google_project_iam_member" "db_user_instance_user_role" {
project = "<プロジェクトID>"
role = "roles/cloudsql.instanceUser"
member = "serviceAccount:<Cloud Runが利用するサービスアカウントemail>"
depends_on = [google_sql_user.db_user]
}
2. マルチコンテナ構成の Cloud Run を作成する
Ingress コンテナとは何か?コンテナ数の制約は?などの説明がされているのでこちらを参照してください。
resource "google_cloud_run_v2_service" "default" {
...
template {
...
service_account = "<Cloud Runが利用するサービスアカウントemail>"
containers {
...
name = "<Ingressコンテナの名前>"
image = "<アプリケーションのイメージ>"
ports {
name = "http1" or "h2c"
container_port = <ポート>
}
# Cloud SQL Auth Proxyの起動後にIngressコンテナを起動する
depends_on = ["<サイドカーコンテナの名前>"]
}
# サイドカーでCloud SQL Auth Proxyを起動する
containers {
...
name = "<サイドカーコンテナの名前>"
image = "gcr.io/cloud-sql-connectors/cloud-sql-proxy:x.x.x"
# https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance#connection_name-1
args = ["--port=5432", "--health-check", "--http-address=0.0.0.0", "--private-ip", "--auto-iam-authn", "<Cloud SQLインスタンスの接続名>"]
# Ingressコンテナのdepends_onがある場合必須(間隔などはお好きに)
startup_probe {
...
http_get {
path = "/startup"
port = 9090
}
}
}
# Directly access to VPC
vpc_access {
network_interfaces {
# https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_network#name-6
network = "<ネットワーク名>"
# https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_subnetwork#name-7
subnetwork = "<サブネット名>"
}
}
}
}
3. 接続
あとはアプリケーションに postgresql://<Cloud Runが利用するサービスアカウントemailの末尾.gserviceaccount.comを取り除いたもの>@localhost:5432/<データベース>
相当の接続設定をすることで IAM データベース認証での接続が可能となります。
おわりに
サイドカーを利用したことは個人的に初めてでした。ユースケースとしては Otel などもあると思いますので色んなケースで利用していきたいなと考えています。
Discussion