Cloud SQL for PostgreSQL の宛先のプライベート IP 接続を構成する

Database Migration Service は、 Private Service Connect を使用して、プライベート IP アドレスで移行先の Cloud SQL インスタンスに接続します。 Private Service Connect を使用すると、移行先データベースを安全な受信接続に公開し、データベースにアクセスできるユーザーを制御できます。

Private Service Connect のネットワークのアーキテクチャの設定は、PSC 対応の移行先 Cloud SQL インスタンスを使用するか、PSC 非対応の移行先 Cloud SQL インスタンスを使用するかによって異なります。

移行先の接続方法の詳細については、 移行先データベースの接続方法の概要をご覧ください

PSC 対応の Cloud SQL インスタンスの Private Service Connect

PSC 対応の Cloud SQL for PostgreSQL 移行先でプライベート接続を使用する手順は次のとおりです。

  1. 移行先インスタンスを作成して構成するときに、プライベート IP を持つ PSC 対応インスタンスとして作成します。既存の Cloud SQL インスタンスを変更して Private Service Connect を有効にすることはできません。
  2. 後で移行先接続プロファイルを作成するときに、 [接続方法の定義] セクションで [プライベート IP] を選択します。

    [**サービス アタッチメント名**] フィールドには、移行先インスタンス用に作成されたサービス アタッチメントが自動的に入力されます。

PSC 非対応の Cloud SQL インスタンスの Private Service Connect

Private Service Connect を有効にして作成されていない Cloud SQL for PostgreSQL 移行先でプライベート IP 接続を使用するには、Database Migration Service と移行先の間でトラフィックをルーティングするための追加のネットワーク コンポーネントを作成する必要があります。 詳細については、 PSC 非対応の Cloud SQL インスタンスのプライベート IP 移行先接続をご覧ください。

ネットワーキングのニーズに 1 つの踏み台仮想マシン(VM)で十分でない場合は、ネットワーク プロデューサーの設定にインスタンス グループを構成します。 詳細については、 マネージド サービスの ネットワーク接続をご覧ください。

必要な Private Service Connect プロデューサーの設定を作成するには、Google Cloud CLI または Terraform 自動化スクリプトを使用することをおすすめします。 コマンドデータを使用する前に、次のように置き換えます。

  • PROJECT_ID:Private Service Connect プロデューサーの設定を作成するプロジェクト。
  • REGION Private Service Connect プロデューサーの設定を作成するリージョン。
  • ZONE:すべてのゾーンリソース(踏み台 VM など)を作成する REGION 内のゾーン。
  • BASTION 作成する踏み台 VM。
  • DB_SUBNETWORK:トラフィックの転送先となるサブネットワーク。サブネットワークは Cloud SQL インスタンスにアクセスできる必要があります。
  • DB_SUBNETWORK_GATEWAY サブネットワークの IPv4 ゲートウェイ。
  • CLOUD_SQL_INSTANCE_CONNECTION_NAMECloud SQL インスタンスの接続名(project:region:name の形式)。
  • PORT:踏み台が基盤となるデータベースを公開するために使用するポート。
  • CLOUD_SQL_INSTANCE_PRIVATE_IP 移行先の Cloud SQL インスタンスのプライベート IP アドレス。

gcloud

次の Bash スクリプトでは、Google Cloud CLI を使用して、移行先データベースの Private Service Connect プロデューサーの設定を作成します。 デフォルト値の一部を調整する必要がある場合があります。たとえば、 Private Service Connect サブネット の CIDR 範囲などです。

#!/bin/bash

# Create the VPC network for the Database Migration Service Private Service Connect.
gcloud compute networks create dms-psc-vpc \
--project=PROJECT_ID \
--subnet-mode=custom

# Create a subnet for the Database Migration Service Private Service Connect.
gcloud compute networks subnets create dms-psc-REGION \
--project=PROJECT_ID \
--range=10.0.0.0/16 --network=dms-psc-vpc \
--region=REGION

# Create a router required for the bastion to be able to install external
# packages (for example, Dante SOCKS server):
gcloud compute routers create ex-router-REGION \
--network dms-psc-vpc \
--project=PROJECT_ID \
--region=REGION

gcloud compute routers nats create ex-nat-REGION \
--router=ex-router-REGION \
--auto-allocate-nat-external-ips \
--nat-all-subnet-ip-ranges \
--enable-logging \
--project=PROJECT_ID \
--region=REGION

# Create the bastion VM.
gcloud compute instances create BASTION \
    --project=PROJECT_ID \
    --zone=ZONE \
    --image-family=debian-11 \
    --image-project=debian-cloud \
    --network-interface subnet=dms-psc-REGION,no-address \
    --network-interface subnet=DB_SUBNETWORK,no-address \
    --metadata=startup-script='#!/bin/bash

# Route the private IP address using the gateway of the database subnetwork.
# Find the gateway for the relevant subnetwork on the VPC network page
# in the Google Cloud console. Click VPC networks and select the database VPC
# to see the details.
ip route add CLOUD_SQL_INSTANCE_PRIVATE_IP via DB_SUBNETWORK_GATEWAY

# Install Dante SOCKS server.
apt-get install -y dante-server

# Create the Dante configuration file.
touch /etc/danted.conf

# Create a proxy.log file.
touch proxy.log

# Add the following configuration for Dante:
cat > /etc/danted.conf << EOF
logoutput: /proxy.log
user.privileged: proxy
user.unprivileged: nobody

internal: 0.0.0.0 port = PORT
external: ens5

clientmethod: none
socksmethod: none

client pass {
        from: 0.0.0.0/0
        to: 0.0.0.0/0
        log: connect error disconnect
}
client block {
        from: 0.0.0.0/0
        to: 0.0.0.0/0
        log: connect error
}
socks pass {
        from: 0.0.0.0/0
        to: CLOUD_SQL_INSTANCE_PRIVATE_IP/32
        protocol: tcp
        log: connect error disconnect
}
socks block {
        from: 0.0.0.0/0
        to: 0.0.0.0/0
        log: connect error
}
EOF

# Start the Dante server.
systemctl restart danted

tail -f proxy.log'

# Create the target instance from the created bastion VM.
gcloud compute target-instances create bastion-ti-REGION \
--instance=BASTION \
--project=PROJECT_ID \
--instance-zone=ZONE \
--network=dms-psc-vpc

# Create a forwarding rule for the backend service.
gcloud compute forwarding-rules create dms-psc-forwarder-REGION \
--project=PROJECT_ID \
--region=REGION \
--load-balancing-scheme=internal \
--network=dms-psc-vpc \
--subnet=dms-psc-REGION \
--ip-protocol=TCP \
--ports=all \
--target-instance=bastion-ti-REGION \
--target-instance-zone=ZONE

# Create a TCP NAT subnet.
gcloud compute networks subnets create dms-psc-nat-REGION-tcp \
--network=dms-psc-vpc \
--project=PROJECT_ID \
--region=REGION \
--range=10.1.0.0/16 \
--purpose=private-service-connect

# Create a service attachment.
gcloud compute service-attachments create dms-psc-svc-att-REGION \
--project=PROJECT_ID \
--region=REGION \
--producer-forwarding-rule=dms-psc-forwarder-REGION \
--connection-preference=ACCEPT_MANUAL \
--nat-subnets=dms-psc-nat-REGION-tcp

# Create a firewall rule allowing the Private Service Connect NAT subnet.
# access the Private Service Connect subnet
gcloud compute \
--project=PROJECT_ID firewall-rules create dms-allow-psc-tcp \
--direction=INGRESS \
--priority=1000 \
--network=dms-psc-vpc \
--action=ALLOW \
--rules=all \
--source-ranges=10.1.0.0/16 \
--enable-logging

# Print out the created service attachment.
gcloud compute service-attachments describe dms-psc-svc-att-REGION \
--project=PROJECT_ID \
--region=REGION

Terraform

次の Bash スクリプトでは、Google Cloud CLI を使用して、移行先データベースの Private Service Connect プロデューサーの設定を作成します。 デフォルト値の一部を調整する必要がある場合があります。たとえば、 Private Service Connect サブネット の CIDR 範囲などです。

variables.tf:

variable "project_id" {
  type        = string
  description = <<DESC
The Google Cloud project in which the setup is created. This should be the same project as
the one that the Cloud SQL instance belongs to.
DESC
}

variable "region" {
  type        = string
  description = "The Google Cloud region in which you create the Private Service Connect
regional resources."
}

variable "zone" {
  type        = string
  description = <<DESC
The Google Cloud zone in which you create the Private Service Connect zonal resources
(should be in the same region as the one specified in the "region" variable).
DESC
}

variable "cloud_sql_instance_name" {
  type        = string
  description = "The Cloud SQL instance name."
}

variable "port" {
  type        = string
  description = "The port that the bastion will use to expose the underlying database."
  default     = "5432"
}

variable "cloud_sql_instance_network" {
  type        = string
  description = <<DESC
The VPC to which the Cloud SQL instance is peered. This is where the bastion will
forward connections to (the destination database needs to be accessible in this VPC).
DESC
}

main.tf:

/* To execute the call:
terraform apply
-var="project_id=PROJECT_ID"
-var="region=REGION"
-var="zone=ZONE"
-var="cloud_sql_instance_name=CLOUD_SQL_INSTANCE_NAME"
-var="port=PORT"
-var="cloud_sql_instance_network=CLOUD_SQL_INSTANCE_NETWORK" */

locals {
  cloud_sql_instance_connection_name = "${var.project_id}:${var.region}:${var.cloud_sql_instance_name}"
}

# Needed for getting the private IP address of the Cloud SQL instance.
data "google_sql_database_instance" "csql_instance" {
  name    = var.cloud_sql_instance_name
  project = var.project_id
}

# Needed for getting the IPv4 gateway of the subnetwork for the database.
data "google_compute_subnetwork" "db_network_subnet" {
  name    = var.cloud_sql_instance_network
  project = var.project_id
  region  = var.region
}

resource "google_compute_network" "psc_sp_network" {
  name                    = "dms-psc-network"
  project                 = var.project_id
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "psc_sp_subnetwork" {
  name    = "dms-psc-subnet"
  region  = var.region
  project = var.project_id

  network = google_compute_network.psc_sp_network.id
  # CIDR range can be lower.
  ip_cidr_range = "10.0.0.0/16"
}

resource "google_compute_subnetwork" "psc_sp_nat" {
  provider = google-beta
  name     = "dms-psc-nat"
  region   = var.region
  project  = var.project_id

  network = google_compute_network.psc_sp_network.id
  purpose = "PRIVATE_SERVICE_CONNECT"
  # CIDR range can be lower.
  ip_cidr_range = "10.1.0.0/16"
}

resource "google_compute_service_attachment" "psc_sp_service_attachment" {
  provider = google-beta
  name     = "dms-psc-svc-att"
  region   = var.region
  project  = var.project_id

  enable_proxy_protocol = false
  connection_preference = "ACCEPT_MANUAL"
  nat_subnets           = [google_compute_subnetwork.psc_sp_nat.id]
  target_service        = google_compute_forwarding_rule.psc_sp_target_direct_rule.id
}

resource "google_compute_forwarding_rule" "psc_sp_target_direct_rule" {
  name       = "dms-psc-fr"
  region     = var.region
  project    = var.project_id
  network    = google_compute_network.psc_sp_network.id
  subnetwork = google_compute_subnetwork.psc_sp_subnetwork.id

  load_balancing_scheme = "INTERNAL"
  ip_protocol           = "TCP"
  all_ports             = true

  target = google_compute_target_instance.psc_sp_target.id

}

resource "google_compute_target_instance" "psc_sp_target" {
  provider = google-beta
  name     = "dms-psc-fr-target"
  zone     = var.zone
  instance = google_compute_instance.psc_sp_bastion.id
  network  = google_compute_network.psc_sp_network.id
}

resource "google_compute_instance" "psc_sp_bastion" {
  name           = "dms-psc-cloud-sql-bastion"
  project        = var.project_id
  machine_type   = "e2-medium"
  zone           = var.zone
  can_ip_forward = true

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  # The incoming NIC defines the default gateway which must be the Private Service Connect subnet.
  network_interface {
    network    = google_compute_network.psc_sp_network.id
    subnetwork = google_compute_subnetwork.psc_sp_subnetwork.id
  }

  # The outgoing NIC which is on the same network as the Cloud SQL instance.
  network_interface {
    network = data.google_compute_subnetwork.db_network_subnet.network
  }

  metadata_startup_script = <<SCRIPT

#!/bin/bash

# Route the private IP address of the database using the gateway of the database subnetwork.
# To find the gateway for the relevant subnetwork, go to the VPC network page
# in the Google Cloud console. Click VPC networks, and select the database VPC
# to see the details.
ip route add ${data.google_sql_database_instance.csql_instance.private_ip_address} \
via ${data.google_compute_subnetwork.db_network_subnet.gateway_address}

# Install Dante SOCKS server.
apt-get install -y dante-server

# Create the Dante configuration file.
touch /etc/danted.conf

# Create a proxy.log file.
touch proxy.log

# Add the following configuration for Dante:
cat > /etc/danted.conf << EOF
logoutput: /proxy.log
user.privileged: proxy
user.unprivileged: nobody

internal: 0.0.0.0 port = ${var.port}
external: ens5

clientmethod: none
socksmethod: none

client pass {
        from: 0.0.0.0/0
        to: 0.0.0.0/0
        log: connect error disconnect
}
client block {
        from: 0.0.0.0/0
        to: 0.0.0.0/0
        log: connect error
}
socks pass {
        from: 0.0.0.0/0
        to: ${data.google_sql_database_instance.csql_instance.private_ip_address}/32
        protocol: tcp
        log: connect error disconnect
}
socks block {
        from: 0.0.0.0/0
        to: 0.0.0.0/0
        log: connect error
}
EOF

# Start the Dante server.
systemctl restart danted

tail -f proxy.log

SCRIPT
}

# Required firewall rules:

/* Firewall rule allowing the Private Service Connect NAT subnet to access
the Private Service Connect subnet. */
resource "google_compute_firewall" "psc_sp_in_fw" {
  name    = "dms-psc-ingress-nat-fw"
  project = var.project_id
  network = google_compute_network.psc_sp_network.id

  log_config {
    metadata = "INCLUDE_ALL_METADATA"
  }

  allow {
    protocol = "all"
  }

  priority  = 1000
  direction = "INGRESS"
  source_ranges = [google_compute_subnetwork.psc_sp_nat.ip_cidr_range]
}

/* The router that the bastion VM uses to install external packages
(for example, Dante SOCKS server). */

resource "google_compute_router" "psc_sp_ex_router" {
  name    = "dms-psc-external-router"
  project = var.project_id
  region  = var.region
  network = google_compute_network.psc_sp_network.id
}

resource "google_compute_router_nat" "psc_sp_ex_router_nat" {
  name    = "dms-psc-external-router-nat"
  project = var.project_id
  region  = var.region
  router  = google_compute_router.psc_sp_ex_router.name

  nat_ip_allocate_option             = "AUTO_ONLY"
  source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"

  log_config {
    enable = true
    filter = "ERRORS_ONLY"
  }
}

outputs.tf:

# The Private Service Connect service attachment.
output "service_attachment" {
  value = google_compute_service_attachment.psc_sp_service_attachment.id
}

後で移行先接続プロファイルを作成するときに、次の操作を行います。

  1. [接続方法の定義] セクションで [プライベート IP] を選択します。
  2. [サービス アタッチメント名] プルダウン メニューから、 [dms-psc-svc-att-REGION] を選択します。