הגדרת קישוריות של כתובת IP פרטית ליעדים של Cloud SQL ל-PostgreSQL

Database Migration Service משתמש ב- Private Service Connect כדי להתחבר למכונת Cloud SQL של היעד באמצעות כתובת IP פרטית. באמצעות Private Service Connect, אתם יכולים לחשוף את מסד הנתונים של היעד לחיבורים מאובטחים נכנסים, ולשלוט במי שיכול לגשת למסד הנתונים.

הגדרת ארכיטקטורת הרשת עבור Private Service Connect משתנה בהתאם לשאלה אם אתם משתמשים במכונת Cloud SQL עם PSC או במכונת Cloud SQL ללא PSC.

מידע נוסף על שיטות חיבור ליעדים זמין במאמר סקירה כללית של שיטות חיבור למסדי נתונים של יעדים.

‫Private Service Connect למכונות Cloud SQL שמופעל בהן PSC

כדי להשתמש בקישוריות פרטית עם יעדים של Cloud SQL ל-PostgreSQL שמופעל בהם PSC, פועלים לפי השלבים הבאים:

  1. כש יוצרים ומגדירים את מכונת היעד, חשוב לוודא שיוצרים אותה כמכונה עם כתובת IP פרטית שמופעל בה PSC. אי אפשר לשנות מופע קיים של Cloud SQL כך שיופעל בו Private Service Connect.
  2. בשלב מאוחר יותר, כש יוצרים את פרופיל החיבור של היעד, בקטע הגדרת שיטת הקישוריות, בוחרים באפשרות כתובת IP פרטית.

    השדה Service attachment name (שם קובץ מצורף לשירות) מאוכלס באופן אוטומטי עם הקובץ המצורף לשירות שנוצר עבור מופע היעד.

‫Private Service Connect למכונות Cloud SQL שלא מופעל בהן PSC

כדי להשתמש בקישוריות של כתובות IP פרטיות ליעדים של Cloud SQL ל-PostgreSQL שלא נוצרו עם Private Service Connect מופעל, צריך ליצור רכיבי רשת נוספים לניתוב תעבורת נתונים בין Database Migration Service לבין היעד. מידע נוסף זמין במאמר קישוריות ליעד של כתובת IP פרטית למכונות Cloud SQL שאינן PSC.

אם מכונה וירטואלית (VM) אחת של Bastion לא מספיקה לצרכים שלכם ברשת, צריך להגדיר קבוצת מכונות להגדרת יצרן הרשת. מידע נוסף זמין במאמר קישוריות לרשת בשירותים מנוהלים.

כדי ליצור את הגדרת הספק הנדרשת של Private Service Connect, מומלץ להשתמש בסקריפטים לאוטומציה של Google Cloud CLI או Terraform. לפני שמשתמשים בנתוני הפקודה, צריך להחליף את הנתונים הבאים:

  • PROJECT_ID עם הפרויקט שבו יוצרים את הגדרת הבעלים של השירות המנוהל ב-Private Service Connect.
  • מחליפים את REGION באזור שבו יוצרים את הגדרת הבעלים של השירות המנוהל ב-Private Service Connect.
  • ZONE עם התחום (zone) בתוך REGION שבו אתם יוצרים את כל המשאבים של התחום (לדוגמה, מכונת ה-bastion).
  • BASTION עם המכונה הווירטואלית של היעד המבוצר שרוצים ליצור.
  • DB_SUBNETWORK עם רשת המשנה שאליה התנועה תועבר. לרשת המשנה צריכה להיות גישה למכונה של Cloud SQL.
  • DB_SUBNETWORK_GATEWAY בכתובת שער ה-IPv4 של רשת המשנה.
  • CLOUD_SQL_INSTANCE_CONNECTION_NAME עם שם החיבור של מופע Cloud SQL (בפורמט project:region:name).
  • PORT עם היציאה ששרת הבסטיון ישתמש בה כדי לחשוף את מסד הנתונים הבסיסי.
  • CLOUD_SQL_INSTANCE_PRIVATE_IP עם כתובת ה-IP הפרטית של מכונת היעד של Cloud SQL.

gcloud

סקריפט ה-Bash הבא משתמש ב-Google Cloud CLI כדי ליצור את הגדרת ה-Producer של Private Service Connect עבור מסד הנתונים של היעד. שימו לב שאולי תצטרכו לשנות חלק מהגדרות ברירת המחדל. לדוגמה, טווח ה-CIDR של רשת המשנה Private Service Connect.

#!/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 כדי ליצור את הגדרת ה-Producer של Private Service Connect עבור מסד הנתונים של היעד. שימו לב שאולי תצטרכו לשנות חלק מהגדרות ברירת המחדל. לדוגמה, טווח ה-CIDR של רשת המשנה Private Service Connect.

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. בקטע Define connectivity method, בוחרים באפשרות Private IP.
  2. בתפריט הנפתח Service attachment name, בוחרים באפשרות dms-psc-svc-att-REGION.