TerraformにおけるPrivate Service Connect と Cloud SQL についてまとめ
実務で調べた際に、ふとTerraformで色んな書き方が散見されたので、深く調べてみた
まずは、目指すべき姿を説明
あるVPCでCloudSQLを公開IPを持たないように構築し、複数のVPCからCloudSQL Auth Proxyで接続をすることができることを目指す
接続するクライアントは、VMということもあれば、Cloud Runなど、PaaSサービスということもある。
まずは、Private Service Connectについての公式ドキュメント
PSCについて、中身は、VPC Peeringに似たものだと思っていたがどうもそうではない様子
接続元のVPCにエンドポイントを構築して、そこから接続しているらしい
逆にVPC Peeringを用いて接続するのは、Private Service Accessのほうのこと
そもそもPSCには、三つのタイプがあり、エンドポイント方式とバックエンド方式とインターフェイス方式がある
CloudSQLは、エンドポイント方式とのこと
ご丁寧に公式ドキュメントあったけど、日本語だとエンドポイントを手動やる方法しか書いてない
英語のドキュメントには、エンドポイントを自動で作る方法書いてあるけど、Terraformでは書かれてない
自動でエンドポイントを構成するのは、ベータ版とのこと
どちらも限定DNSを構成しているが、こちらもTerraformで書かれてない。
そして Cloud SQL Auth Proxyで接続した場合は、限定DNSを構成する必要があるとのこと
これは、まぁTerraformでかける
皆の味方 Terraform のGoogle Cloud のプロバイダーのドキュメント
手動は公式に書いてあるので、自動でエンドポイントを作る方法をTerraform化してみる
そもそも sevice connection policyとは、
サービス接続ポリシーは、リージョンの Google Cloud リソースです。これにより、ネットワーク管理者は、サービス接続の自動化を通じてデプロイおよび接続できるプロデューサー サービスを指定できます。マネージド サービスにサービス接続ポリシーが存在する場合、コンシューマー サービス管理者はそのサービスをデプロイできます。
検証してみたけど、CloudSQLにPrivate IPが付与されてない
公式ドキュメントのgcloudコマンドを見ると、知らないオプションを指定してる
--psc-auto-connections
これは、Terraformのプロバイダーには、これに該当するものがないかな...
しょうがないので、現状手動で構成する
CloudSQLの例
resource "google_sql_database_instance" "default" {
name = "mysql-instance"
region = "us-central1"
database_version = "MYSQL_8_0"
settings {
tier = "db-f1-micro"
availability_type = "REGIONAL"
backup_configuration {
enabled = true
binary_log_enabled = true
}
ip_configuration {
psc_config {
psc_enabled = true
allowed_consumer_projects = []
}
ipv4_enabled = false
}
}
deletion_protection = false # Set to "true" to prevent destruction of the resource
}
エンドポイントで使う内部IPアドレスを予約して、NATで、CloudSQLのサービスアタッチメントに紐づける
resource "google_compute_address" "default" {
name = "psc-compute-address-${google_sql_database_instance.default.name}"
region = "us-central1"
address_type = "INTERNAL"
subnetwork = "default" # Replace value with the name of the subnet here.
address = "10.128.0.43" # Replace value with the IP address to reserve.
}
data "google_sql_database_instance" "default" {
name = resource.google_sql_database_instance.default.name
}
resource "google_compute_forwarding_rule" "default" {
name = "psc-forwarding-rule-${google_sql_database_instance.default.name}"
region = "us-central1"
network = "default"
ip_address = google_compute_address.default.self_link
load_balancing_scheme = ""
target = data.google_sql_database_instance.default.psc_service_attachment_link
}
結構大事なのは、リージョンの指定である
この書き方だと、同じリージョンじゃないと、PSC接続できない
もしグローバルでやるなら、この書き方になりそう
resource "google_compute_global_address" "default" {
provider = google-beta
name = "global-psconnect-ip"
address_type = "INTERNAL"
purpose = "PRIVATE_SERVICE_CONNECT"
network = google_compute_network.network.id
address = "100.100.100.105"
}
data "google_sql_database_instance" "default" {
name = resource.google_sql_database_instance.default.name
}
resource "google_compute_global_forwarding_rule" "default" {
provider = google-beta
project = google_compute_network.network.project
name = "globalrule"
target = data.google_sql_database_instance.default.psc_service_attachment_link
network = google_compute_network.network.id
ip_address = google_compute_global_address.default.id
load_balancing_scheme = ""
}
正直dataは、冗長。普通に指定できる
コンシューマー(CloudSQLにアクセスするクライアント)のVPCに限定公開DNSゾーンを構築する必要がある
それをterraform化してみよう
CloudSQLのDNS名を取得
限定公開DNSゾーンを構築
レコードをセット
data "google_sql_database_instance" "default" {
name = resource.google_sql_database_instance.default.name
}
resource "google_dns_managed_zone" "private-zone" {
name = "private-zone"
dns_name = "${var.region}.sql.goog."
description = "CloudSQL private DNS zone"
visibility = "private"
private_visibility_config {
networks {
network_url = google_compute_network.consumer.id
}
}
}
resource "google_dns_record_set" "a" {
name = data.google_sql_database_instance.default.dns_name
managed_zone = google_dns_managed_zone.private_zone.name
type = "A"
ttl = 300
rrdatas = [google_compute_address.address]
}