作業端末から本番環境の Cloud SQL, AlloyDB のプライベート IP インスタンスへのアクセス
クラウドエースの北野です。
SSH ポートフォワーディングによるローカル端末から Cloud SQL と AlloyDB のプライベート IP インスタンスにアクセスする方法を紹介します。
概要
ローカル端末から インスタンスにアクセスするシステム構成は以下の通りです。
- COS インスタンス上の Auth Proxy プロセスによる Cloud SQL, AlloyDB インスタンスへの接続
- 作業端末から COS インスタンスへの SSH ポートフォーワーディグによる Cloud SQL, AlloyDB インスタンスへの接続
Compute Engine に SSH ポートフォワーディングするコマンド
gcloud compute ssh --tunnel-through-iap <GCENAME> -- -N -L 5432:localhost:5432 &
はじめに
本番環境のデータベースはセキュリティの観点からパブリック IP を付与しない構成になっているかと思います。
Google Cloud の RDB サービスである Cloud SQL, AlloyDB もプライベート IP のみを持つインスタンスを作成することができます。
しかし、プライベート IP しか持たない Cloud SQL, AlloyDB インスタンスは、インターネットからアクセスができないため、
インスタンスに接続できる VPC ネットワークからアクセスする必要があります。
そのため、ローカル端末からアクセスするとき、VPC ネットワークに踏み台インスタンスを作成しリモートアクセスして、
そこから Cloud SQL インスタンスに接続し操作されていることも多いかと思います。
しかし、この方法で開発をすると、踏み台端末で使い慣れたツールを使えないため、作業ミスをしたり作業効率が悪かったりします。
本記事では、ローカル端末で Cloud SQL, AlloyDB のプライベート IP インスタンスを操作する方法を紹介します。
システムの設計
この問題を Cloud Identity-Aware Proxy for TCP の SSH 接続である SSH ポートフォワーディングによって解決します。
SSH ポートフォワーディングでローカルの作業端末から Compute Engine 上の Auth Proxy プロセスにトンネルを作成し、
このトンネルを使って作業端末から Cloud SQL, AlloyDB インスタンスに接続します。
Cloud Identity-Aware Proxy for TCP の SSH 接続で Cloud SQL インスタンスに接続するシステムの構成は以下のようになります。
Auth Proxy により Cloud SQL に接続する Compute Engine の種類に指定はありませんが、
Auth Proxy をインストールし、接続するプロセスを起動する必要があります。
本記事では接続のみを実施し、簡単に接続する環境を紹介するため、Compute Engine に Container Optimized OS で実現する方法を紹介します。
また、本記事では Cloud SQL, AlloyDB と VPC ネットワークの接続は、
Private Service Access により接続し、プライベート IP での接続を実現します。
コンテナイメージの取得のための外部アクセスについても、Cloud NAT を使いインターネットへの外部アクセスを許可して取得ようにします。
以下では、Cloud SQL インスタンスへのローカル端末からの接続方法を具体的に紹介します。
VPC ネットワークの構築
ここでは、以下のネットワークリソースを作成します。
- VPC Network
- Firewall Policy
- Cloud NAT
- Private Service Access
Identity-Aware Proxy を使うため、IAP サーバーからのアクセスを許可するファイアーウォールを作成する必要があります。
上記のそれぞれのリソースを作成する Terraform コードは、以下の通りです。
- VPCネットワークの作成
resource "google_compute_network" "main" {
name = "private-instance"
project = var.project
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "main" {
name = "private-instance-tkyo"
project = var.project
region = "asia-northeast1"
network = google_compute_network.main.id
ip_cidr_range = "192.168.0.0/24"
}
- Firewall Policy の作成
data "google_netblock_ip_ranges" "iap" {
range_type = "iap-forwarders"
}
resource "google_compute_network_firewall_policy" "main" {
name = "secure"
project = var.project
}
resource "google_compute_network_firewall_policy_association" "main" {
name = "secure"
project = var.project
attachment_target = google_compute_network.main.id
firewall_policy = google_compute_network_firewall_policy.main.name
}
resource "google_compute_network_firewall_policy_rule" "iap" {
firewall_policy = google_compute_network_firewall_policy.main.name
rule_name = "1000-in-ok-iap-ssh"
project = var.project
action = "allow"
direction = "INGRESS"
priority = 1000
target_service_accounts = [
google_service_account.main.email
]
match {
src_ip_ranges = data.google_netblock_ip_ranges.iap.cidr_blocks_ipv4
layer4_configs {
ip_protocol = "tcp"
ports = ["22"]
}
}
}
- Private Service Access の作成
resource "google_compute_global_address" "main" {
name = "psa-cloudsql"
project = var.project
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = "20"
address = "172.16.0.0"
network = google_compute_network.main.id
}
resource "google_service_networking_connection" "main" {
network = google_compute_network.main.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.main.name]
deletion_policy = "ABANDON"
}
- NAT の作成
resource "google_compute_router" "main" {
name = "private-sqlinstance"
project = var.project
region = "asia-northeast1"
network = google_compute_network.main.id
}
resource "google_compute_router_nat" "main" {
name = "private-sqlinstance"
project = var.project
router = google_compute_router.main.name
region = "asia-northeast1"
nat_ip_allocate_option = "MANUAL_ONLY"
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
nat_ips = [google_compute_address.main.self_link]
}
resource "google_compute_address" "main" {
name = "nat-private-sqlinstance"
project = var.project
region = "asia-northeast1"
}
Cloud SQL, AlloyDB インスタンスの作成
Cloud SQL のプライベート IP インスタンスの作成は以下の通りです。
resource "google_sql_database_instance" "main" {
name = "private-ip-instance"
project = var.project
database_version = "POSTGRES_15"
region = "asia-northeast1"
deletion_protection = false
settings {
tier = "db-f1-micro"
ip_configuration {
ipv4_enabled = false
private_network = google_compute_network.main.self_link
enable_private_path_for_google_cloud_services = true
}
}
depends_on = [
google_service_networking_connection.main
]
}
Compute Engine の作成
Auth Proxy を起動する Compute Engine は、Container Optimized OS (COS) 上に Auth Proxy のコンテナを作成して Cloud SQL インスタンスに接続させます。
本記事では、COS のメタデータ user-data
に cloud-init
を定義し Auth Proxy のコンテナを起動します。
Auth Proxy のコンテナを起動する cloud-init の定義は以下の通りです。
#cloud-config
write_files:
- path: /etc/systemd/system/accept-tcp${sql_instance.port}-firewall.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Accept tcp ${sql_instance.port}
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/sbin/iptables -A INPUT -p tcp --dport ${sql_instance.port} -j ACCEPT
- path: /etc/systemd/system/authproxy.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Start AuthProxy container
After=docker.service accept-tcp${sql_instance.port}-firewall.service
Wants=docker.service accept-tcp${sql_instance.port}-firewall.service
[Service]
ExecStop=/usr/bin/docker stop authproxy.service
ExecStart=/usr/bin/docker run --rm --network host -p ${sql_instance.port}:${sql_instance.port} --name authproxy gcr.io/cloud-sql-connectors/cloud-sql-proxy --private-ip ${sql_instance.uri}
runcmd:
- systemctl daemon-reload
- systemctl start authproxy.service
上記のファイルを cloud-init.yaml として保存し、Terraform から呼び出します。
resource "google_compute_instance" "main" {
name = <GCENAME>
project = var.project
zone = "asia-northeast1-b"
machine_type = "e2-micro"
boot_disk {
auto_delete = true
initialize_params {
image = "cos-cloud/cos-stable"
}
}
network_interface {
subnetwork = google_compute_subnetwork.main.id
}
service_account {
email = google_service_account.main.email
scopes = ["cloud-platform"]
}
metadata = {
enable-oslogin = true
user-data = templatefile("cloud-init.yaml", {
sql_instance = {
port = 5432
uri = google_sql_database_instance.main.connection_name
}
})
}
}
resource "google_service_account" "main" {
account_id = "gce-proxy"
project = var.project
}
resource "google_project_iam_member" "main" {
project = var.project
role = "roles/cloudsql.client
member = google_service_account.main.member
}
作業端末からの Cloud SQL インスタンスへの接続
最後に Cloud Identity-Aware Proxy for TCP の SSH 接続による Cloud SQL インスタンスに接続してみます。
Cloud Identity-Aware Proxy for TCP の SSH 接続による SSH のポートフォワーディングは、以下のコマンドでトンネルを作成します。
gcloud compute ssh --tunnel-through-iap <GCENAME> -- -N -L 5432:localhost:5432 &
最後に作業端末から psql コマンドで接続してみます。
❯ psql -h localhost -p 5432 -U postgres
Password for user postgres:
psql (14.13 (Homebrew), server 15.8)
WARNING: psql major version 14, server major version 15.
Some psql features might not work.
Type "help" for help.
postgres=>
さいごに
Cloud SQL のプライベート IP インスタンスに作業端末からアクセスする方法について、紹介しました。
AlloyDB も同じように COS 上に gcr.io/alloydb-connectors/alloydb-auth-proxy のイメージを使い Auth Proxy コンテナを作成し SSH ポートフォワーディングを通じてアクセスさせることができます。
また、Datastream で連携させるのも同じように COS インスタンスをプロキシさせて同期させることができます。
Discussion