How to connect Cloud Run to a Private Cloud SQL Instance
Connecting Google Cloud Run to a private Cloud SQL instance requires careful networking configuration to ensure secure, private communication between your containerised application and database. This guide walks through the essential steps using Terraform infrastructure as code.
Overview
A private Cloud SQL instance provides enhanced security by eliminating public IP addresses and restricting access to only resources within your VPC network. This approach is ideal for production workloads where database security is paramount.
Source Code
You could find all code related to this post in Github.
Implementation
For connecting Cloud run to a private Cloud SQL instance we are going to follow these 5 steps:
- Create a Private VPC Network – Set up a custom VPC network with dedicated subnets for your resources
- Configure VPC Peering for Cloud SQL – Establish private service networking connection to allow Cloud SQL access
- Deploy Private Cloud SQL Instance – Create the database instance with private IP only (no public access)
- Configure Cloud Run with VPC Access – Connect your Cloud Run job to the private network and mount Cloud SQL volumes
- Set Up Service Account Permissions – Grant necessary IAM roles for Cloud SQL client access
1. Private VPC Network Setup
First, let’s create a dedicated VPC network with custom subnets:
resource "google_compute_network" "private_network" {
name = "private-network"
project = var.project
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "default" {
project = var.project
name = "test-subnetwork"
ip_cidr_range = "10.2.0.0/16"
region = var.region
network = google_compute_network.private_network.id
}
2. VPC Peering for Cloud SQL
Configure VPC peering to allow Cloud SQL to communicate within your private network:
resource "google_compute_global_address" "private_ip_address" {
name = "private-ip-address"
project = var.project
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = google_compute_network.private_network.id
}
resource "google_service_networking_connection" "private_vpc_connection" {
network = google_compute_network.private_network.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.private_ip_address.name]
}
3. Private Cloud SQL Instance
Create the Cloud SQL instance with private networking enabled:
resource "google_sql_database_instance" "postgres_instance" {
name = var.instance_name
database_version = var.database_version
region = var.region
project = var.project
deletion_protection = false
depends_on = [google_service_networking_connection.private_vpc_connection]
settings {
tier = var.tier
ip_configuration {
ipv4_enabled = false
private_network = google_compute_network.private_network.id
}
disk_size = var.disk_size
disk_type = var.disk_type
disk_autoresize = false
}
}
Key configuration points:
– Set `ipv4_enabled = false` to disable public IP access
– Reference your private network in `private_network`
4. Cloud Run Job with VPC Access
Configure your Cloud Run job to connect to the private network:
resource "google_cloud_run_v2_job" "k6" {
project = var.project
name = "k6-test"
location = var.region
depends_on = [docker_image.k6, docker_registry_image.k6]
template {
parallelism = 1
task_count = 1
template {
service_account = google_service_account.k6.email
timeout = "86400s"
max_retries = 1
vpc_access {
network_interfaces {
network = google_compute_network.private_network.name
subnetwork = google_compute_subnetwork.default.name
}
}
containers {
env {
name = "DB_USER"
value = var.db_user
}
env {
name = "DB_PASSWORD"
value = var.db_password
}
env {
name = "DB_HOST"
value = google_sql_database_instance.postgres_instance.private_ip_address
}
env {
name = "DB_NAME"
value = var.database_name
}
image = "${local.docker-image}:latest"
args = ["/k6", "run", "script.js"]
volume_mounts {
name = "cloudsql"
mount_path = "/cloudsql"
}
}
volumes {
name = "cloudsql"
cloud_sql_instance {
instances = [google_sql_database_instance.postgres_instance.connection_name]
}
}
}
}
}
Key configuration points:
- Create a Cloud SQL connector by mounting the cloud sql volume
- Run Cloud Run in the network created in step 1
5. Service Account Permissions
Ensure your Cloud Run service account has the necessary permissions:
resource "google_service_account" "k6" {
project = var.project
account_id = "ksix-sa"
display_name = "Service Account"
}
resource "google_project_iam_member" "k6_sql_client" {
project = var.project
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.k6.email}"
}
Connection Methods
To connect from Cloud Run to your Cloud SQL instance you can use the private IP address of your Cloud SQL instance:
const connectionString = `postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/${DB_NAME}?sslmode=disable`;
Where `DB_HOST` is the private IP address from `google_sql_database_instance.postgres_instance.private_ip_address`.
Summary
This configuration provides a secure, scalable foundation for connecting Cloud Run applications to private Cloud SQL instances while maintaining network isolation and following Google Cloud security best practices.
Recent Comments