diff --git a/deploy/terraform-custom-datacommons/modules/locals.tf b/deploy/terraform-custom-datacommons/modules/locals.tf index f26cdc540a..95e0dd812a 100644 --- a/deploy/terraform-custom-datacommons/modules/locals.tf +++ b/deploy/terraform-custom-datacommons/modules/locals.tf @@ -48,6 +48,10 @@ locals { name = "CLOUDSQL_INSTANCE" value = google_sql_database_instance.mysql_instance.connection_name }, + { + name = "CLOUDSQL_USE_PRIVATE_IP" + value = tostring(var.mysql_use_private_ip) + }, { name = "DB_NAME" value = var.mysql_database_name diff --git a/deploy/terraform-custom-datacommons/modules/main.tf b/deploy/terraform-custom-datacommons/modules/main.tf index b85d9df632..30a8ce1d76 100644 --- a/deploy/terraform-custom-datacommons/modules/main.tf +++ b/deploy/terraform-custom-datacommons/modules/main.tf @@ -45,6 +45,45 @@ resource "google_redis_instance" "redis_instance" { replica_count = var.redis_replica_count } +# Enable Service Networking API for private IP +resource "google_project_service" "servicenetworking" { + count = var.mysql_use_private_ip ? 1 : 0 + service = "servicenetworking.googleapis.com" + + disable_on_destroy = false +} + +# Allocate IP address range for private service connection +resource "google_compute_global_address" "private_ip_address" { + count = var.mysql_use_private_ip ? 1 : 0 + name = "${var.namespace}-cloudsql-private-ip" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = var.mysql_private_ip_prefix_length + network = data.google_compute_network.default.id +} + +# Create private VPC connection for Cloud SQL +resource "google_service_networking_connection" "private_vpc_connection" { + count = var.mysql_use_private_ip ? 1 : 0 + network = data.google_compute_network.default.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.private_ip_address[0].name] + + depends_on = [google_project_service.servicenetworking] +} + +# Configure peering routes for private connection +resource "google_compute_network_peering_routes_config" "cloudsql_peering_routes" { + count = var.mysql_use_private_ip ? 1 : 0 + peering = google_service_networking_connection.private_vpc_connection[0].peering + network = data.google_compute_network.default.name + project = var.project_id + + export_custom_routes = true + import_custom_routes = true +} + # Create MySQL instance resource "google_sql_database_instance" "mysql_instance" { name = "${var.namespace}-${var.mysql_instance_name}" @@ -62,7 +101,12 @@ resource "google_sql_database_instance" "mysql_instance" { } ip_configuration { - ipv4_enabled = true + ipv4_enabled = !var.mysql_use_private_ip + private_network = var.mysql_use_private_ip ? data.google_compute_network.default.id : null + # Use the allocated IP range for private connections + allocated_ip_range = var.mysql_use_private_ip ? google_compute_global_address.private_ip_address[0].name : null + # Enable private path for better performance with Google Cloud services + enable_private_path_for_google_cloud_services = var.mysql_use_private_ip } disk_size = var.mysql_storage_size_gb @@ -70,6 +114,11 @@ resource "google_sql_database_instance" "mysql_instance" { } deletion_protection = var.mysql_deletion_protection + + depends_on = [ + google_service_networking_connection.private_vpc_connection, + google_compute_network_peering_routes_config.cloudsql_peering_routes + ] } # Generate random mysql password diff --git a/deploy/terraform-custom-datacommons/modules/variables.tf b/deploy/terraform-custom-datacommons/modules/variables.tf index 654f9c609e..54e14ce0ce 100644 --- a/deploy/terraform-custom-datacommons/modules/variables.tf +++ b/deploy/terraform-custom-datacommons/modules/variables.tf @@ -151,6 +151,24 @@ variable "mysql_deletion_protection" { # Data Commons Cloud Run service variables +variable "mysql_use_private_ip" { + description = "Set Cloud Run containers to connect to MySQL using private IP (internal VPC) instead of public IP" + type = bool + default = false +} + +# See https://docs.cloud.google.com/sql/docs/mysql/configure-private-services-access +variable "mysql_private_ip_prefix_length" { + description = "The prefix length of the IP range for the Cloud SQL private connection. Google automatically selects an available address block of this size. Must be between 16 and 24." + type = number + default = 24 + + validation { + condition = var.mysql_private_ip_prefix_length >= 16 && var.mysql_private_ip_prefix_length <= 24 + error_message = "The mysql_private_ip_prefix_length must be between 16 and 24. Cloud SQL requires at least /24." + } +} + variable "dc_web_service_image" { description = "Container image for Cloud Run service" type = string