Logo GCP con Eduardo

GCP con Eduardo

Descarga el código de la lección

Desplegar Base de Datos PRIVADA en GCP con Terraform (Cloud SQL Postgres + VPC Peering)
✦ Guía Técnica & Arquitectura

Desplegar Base de Datos PRIVADA en GCP con Terraform: Cloud SQL PostgreSQL + VPC Peering

Diseña una arquitectura de Cloud SQL PostgreSQL sin exposición a Internet, automatizada con Terraform y conectada mediante Private Service Access. La clave no es simplemente activar Private IP: es construir correctamente la relación entre VPC, rango reservado, Service Networking y Cloud SQL para obtener una plataforma reproducible, segura y operable.

Lo que aprenderás

Crear una VPC dedicada y preparar Private Service Access con Terraform.
Reservar correctamente el rango CIDR destinado a los servicios gestionados de Google.
Desplegar Cloud SQL PostgreSQL con ipv4_enabled = false y conectividad privada.
Operar la instancia mediante Cloud SQL Studio sin convertir la base de datos en un endpoint público.
GCP Cloud SQL PostgreSQL Terraform VPC Private Service Access VPC Peering Cloud SQL Studio

La arquitectura: una base de datos que no necesita Internet

El objetivo es eliminar la IP pública de Cloud SQL y hacer que las aplicaciones que viven en la VPC consuman PostgreSQL mediante una dirección IP privada. Google Cloud recomienda Private IP cuando los clientes están dentro de una VPC o tienen conectividad privada hacia ella.

En este diseño, Private Service Access establece una conexión privada mediante VPC Network Peering entre nuestra VPC y la red administrada por Google que proporciona el servicio. El rango de direcciones reservado con propósito VPC_PEERING permite que Google asigne las direcciones internas utilizadas por Cloud SQL.

┌──────────────────────────────────────────────────────────────┐ │ Google Cloud │ │ │ │ ┌────────────────────── VPC ─────────────────────────┐ │ │ │ │ │ │ │ Application / GKE / Compute Engine / VM │ │ │ │ │ │ │ │ │ │ Private IP │ │ │ │ ▼ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ Private Service │ │ │ │ │ │ Access │ │ │ │ │ └──────────┬──────────┘ │ │ │ │ │ VPC Network Peering │ │ │ └──────────────────┼─────────────────────────────────┘ │ │ │ │ │ Google Service Network │ │ │ │ │ ┌───────▼────────┐ │ │ │ Cloud SQL │ │ │ │ PostgreSQL │ │ │ │ Private IP │ │ │ └────────────────┘ │ │ │ │ No public IPv4 address exposed │ └──────────────────────────────────────────────────────────────┘

La consecuencia arquitectónica importante es que la base de datos deja de ser un recurso que debemos proteger desde Internet mediante listas de IP públicas y pasa a formar parte del plano de red privado de nuestra arquitectura.

Matriz de decisión: ¿Public IP, Private IP o PSC?

Patrón Exposición Conectividad Seguridad Complejidad Cuándo utilizarlo
Public IP Internet Endpoint IPv4 público Depende de authorized networks / TLS / conectores Baja Clientes externos que no tienen conectividad privada.
Sin endpoint público VPC + Service Networking Media
Private Service Connect Sin exposición pública Endpoint PSC Segmentación y control avanzado Alta Escenarios donde se necesita publicar/consumir servicios mediante endpoints PSC.
VPN / Interconnect + Private IP Sin Internet pública para DB Red híbrida privada Alta Datacenters, oficinas o VPC externas con conectividad híbrida.

Para Cloud SQL PostgreSQL, Private Service Access requiere una conexión privada previamente establecida sobre la VPC. La documentación de Google muestra Terraform mediante google_compute_global_address, google_service_networking_connection y google_sql_database_instance.

Private Service Access no es simplemente "activar Private IP"

Este es uno de los puntos donde aparecen más errores en implementaciones Terraform. Cloud SQL no puede utilizar una VPC arbitraria con Private IP si antes no existe la infraestructura de Private Service Access.

El flujo lógico es:

VPC

Crear la red que alojará los consumidores de la base de datos.

Rango reservado

Reservar un bloque CIDR con propósito VPC_PEERING para servicios gestionados.

Service Networking

Crear google_service_networking_connection contra servicenetworking.googleapis.com.

Cloud SQL

Asociar PostgreSQL a la VPC y deshabilitar la dirección IPv4 pública.

Operación

Utilizar Cloud SQL Studio, IAM y autenticación de base de datos para administrar los datos.

⚠️ Antipatrón crítico: creer que "Private IP" significa aislamiento automático

Tener una dirección privada no significa que cualquier componente de la arquitectura esté correctamente segmentado. El aislamiento depende de quién tiene rutas hacia la VPC, qué rangos están anunciados, qué identidades pueden autenticarse y qué reglas de red permiten el tráfico.

Otro error frecuente consiste en crear el google_sql_database_instance antes de que exista la conexión de Service Networking. En Terraform esto puede producir carreras de provisión o errores de operación.

Solución: modela explícitamente la dependencia mediante depends_on, reserva un rango suficientemente dimensionado y evita diseñar el rango de PSA solapado con las subredes que utilizarán tus workloads.

Además, no habilites una IP pública "solo para probar" en producción: la configuración de red debería ser reproducible desde Terraform y el acceso operativo debería resolverse con los mecanismos de autenticación y administración previstos.

Implementación de producción con Terraform

El siguiente ejemplo crea una VPC custom, una subred para workloads, un rango reservado para Private Service Access, la conexión de Service Networking y finalmente una instancia PostgreSQL de Cloud SQL sin IP pública.

terraform {
  required_version = ">= 1.6.0"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 6.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

variable "project_id" {
  type = string
}

variable "region" {
  type    = string
  default = "europe-west1"
}

resource "google_compute_network" "private_vpc" {
  name                    = "data-private-vpc"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "apps" {
  name          = "data-apps-subnet"
  ip_cidr_range = "10.20.0.0/24"
  region        = var.region
  network       = google_compute_network.private_vpc.id

  private_ip_google_access = true
}

# Rango reservado exclusivamente para
# Private Service Access / VPC Peering.
resource "google_compute_global_address" "private_services" {
  name          = "google-managed-services-data"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16

  network = google_compute_network.private_vpc.id
}

# Conexión privada entre nuestra VPC y
# la red de servicios administrados de Google.
resource "google_service_networking_connection" "private_vpc_connection" {
  network = google_compute_network.private_vpc.id
  service = "servicenetworking.googleapis.com"

  reserved_peering_ranges = [
    google_compute_global_address.private_services.name
  ]
}

resource "google_sql_database_instance" "postgres" {
  name             = "private-postgres"
  region           = var.region
  database_version = "POSTGRES_17"

  # La dependencia evita intentar crear Cloud SQL
  # antes de disponer de Private Service Access.
  depends_on = [
    google_service_networking_connection.private_vpc_connection
  ]

  settings {
    tier              = "db-custom-2-8192"
    availability_type = "REGIONAL"

    backup_configuration {
      enabled                        = true
      point_in_time_recovery_enabled = true
    }

    ip_configuration {
      # Sin dirección IPv4 pública.
      ipv4_enabled = false

      # Cloud SQL utilizará la VPC privada.
      private_network = google_compute_network.private_vpc.id

      # Evita que una configuración de red posterior
      # introduzca accidentalmente rangos públicos.
      enable_private_path_for_google_cloud_services = true
    }

    maintenance_window {
      day          = 7
      hour         = 3
      update_track = "stable"
    }
  }

  deletion_protection = true
}

resource "google_sql_database" "application" {
  name     = "application"
  instance = google_sql_database_instance.postgres.name
}

output "vpc_name" {
  value = google_compute_network.private_vpc.name
}

output "postgres_private_ip" {
  value     = google_sql_database_instance.postgres.private_ip_address
  sensitive = true
}

output "postgres_connection_name" {
  value = google_sql_database_instance.postgres.connection_name
}

La propiedad fundamental es ipv4_enabled = false. La instancia queda configurada para conectividad privada y utiliza private_network para asociarse a la VPC.

En producción también conviene mantener deletion_protection = true y definir explícitamente backups, recuperación point-in-time, ventana de mantenimiento, disponibilidad y sizing según los SLO reales de la aplicación.

Un detalle importante: las rutas de VPC Peering

En arquitecturas donde se utilizan rutas personalizadas o escenarios de networking más complejos, puede ser necesario gestionar explícitamente las rutas importadas y exportadas de la conexión de peering.

El patrón de Terraform utilizado por Google para determinados escenarios de Cloud SQL Private IP contempla google_compute_network_peering_routes_config.

resource "google_compute_network_peering_routes_config" "private_services_routes" {
  peering = google_service_networking_connection.private_vpc_connection.peering
  network = google_compute_network.private_vpc.name

  import_custom_routes = true
  export_custom_routes = true
}

No debes añadir este recurso mecánicamente a todas las arquitecturas. La decisión depende de si necesitas intercambiar rutas personalizadas a través del peering. El principio correcto es habilitar únicamente la propagación de rutas necesaria para el diseño.

¿Qué ocurre realmente con el tráfico?

Desde una VM, GKE u otro workload con acceso a la VPC, el cliente resuelve la dirección privada de Cloud SQL y el tráfico permanece dentro de la infraestructura privada de Google Cloud.

APP │ │ TCP / PostgreSQL ▼ 10.20.0.0/24 │ │ VPC routing ▼ Private Service Access │ │ VPC Network Peering ▼ Google Service Producer Network │ ▼ Cloud SQL PostgreSQL Private IP NO: APP → Internet → Public IP → PostgreSQL

Esto reduce la superficie de exposición. No necesitas publicar un endpoint PostgreSQL en Internet únicamente porque una aplicación necesite acceder a la base de datos.

Para conectividad híbrida, el patrón puede extenderse mediante VPN o Cloud Interconnect, siempre que exista conectividad hacia la VPC donde está establecido Private Service Access.

Cloud SQL Studio: administración sin abrir PostgreSQL a Internet

Una pregunta habitual después de eliminar la IP pública es: ¿cómo administro entonces la base de datos?

Cloud SQL Studio permite interactuar con Cloud SQL directamente desde la consola de Google Cloud. Para PostgreSQL, proporciona Explorer, editor SQL y resultados de consultas, permitiendo ejecutar DDL, DML y DQL.

El acceso no implica convertir la instancia en pública. Cloud SQL Studio utiliza el plano de administración de Google Cloud y exige los permisos IAM correspondientes. El rol específico de usuario de Cloud SQL Studio es roles/cloudsql.studioUser.

# Ejemplo conceptual de IAM para un operador:

resource "google_project_iam_member" "cloud_sql_studio_user" {
  project = var.project_id
  role    = "roles/cloudsql.studioUser"
  member  = "user:operador@example.com"
}

Después de desplegar la instancia, el flujo operativo es: seleccionar la instancia en Cloud SQL, abrir Cloud SQL Studio, seleccionar la base de datos y autenticarse mediante IAM Database Authentication o mediante las credenciales del usuario PostgreSQL.

Para consultas de producción pesadas, Cloud SQL Studio no debería sustituir a un cliente especializado: la herramienta está orientada a consultas ligeras y tiene limitaciones operativas, entre ellas un límite de cinco minutos para las solicitudes y truncamiento de respuestas superiores a 10 MB.

Patrones de diseño y mejores prácticas

1. Separar la red de aplicaciones del rango de PSA

No utilices el mismo rango CIDR para las subredes de aplicaciones y para el espacio reservado a Google-managed services. El rango de PSA debe tratarse como un bloque dedicado de infraestructura.

2. Diseñar el CIDR pensando en expansión

Cloud SQL puede necesitar espacio para diferentes instancias y regiones. Dimensionar demasiado agresivamente el rango reservado puede convertirse en un problema de capacidad años después del primer despliegue.

3. Evitar la IP pública como mecanismo de administración

El acceso administrativo debe diseñarse alrededor de IAM, Cloud SQL Studio, conectividad privada, Cloud SQL Auth Proxy o mecanismos de acceso controlado según el caso de uso.

4. Terraform debe controlar el grafo de dependencias

VPC → rango reservado → Service Networking → Cloud SQL es una dependencia arquitectónica, no un detalle cosmético. Expresarla correctamente reduce fallos durante terraform apply.

5. Mantener la región alineada

Mantener los consumidores y Cloud SQL en regiones coherentes reduce latencia y evita costes innecesarios de transferencia interregional. La decisión final debe basarse en requisitos de disponibilidad, residencia de datos y disaster recovery.

6. Gobernar los permisos por identidad

El aislamiento de red no sustituye IAM. Un operador con acceso excesivo puede seguir siendo un riesgo aunque PostgreSQL no tenga una IP pública. Aplica mínimo privilegio tanto en Google Cloud como dentro de PostgreSQL.

Checklist de implementación empresarial

Definir el modelo de red

Determina VPC, subredes, regiones, CIDRs, conectividad híbrida y consumidores autorizados.

Reservar CIDR para PSA

Crea un rango interno dedicado con propósito VPC_PEERING.

Crear Service Networking

Establece google_service_networking_connection con servicenetworking.googleapis.com.

Desplegar Cloud SQL

Configura private_network y ipv4_enabled = false.

Proteger el ciclo de vida

Activa backups, PITR, deletion protection, mantenimiento controlado y monitorización.

Configurar IAM

Define quién puede administrar la instancia, ejecutar SQL y modificar infraestructura.

Validar conectividad

Comprueba DNS, rutas, IP privada, conectividad desde los workloads y ausencia de IP pública.

Validar Cloud SQL Studio

Accede desde la consola, autentica el usuario y ejecuta una consulta de validación.

Automatizar con CI/CD

Ejecuta Terraform mediante pipelines con revisión, plan, aprobación y estado remoto protegido.

FinOps: dónde se puede encarecer esta arquitectura

Private IP no significa que la red sea gratuita. El coste global depende principalmente del tamaño y configuración de Cloud SQL, almacenamiento, backups, alta disponibilidad, transferencia de datos y otros servicios asociados.

Una de las optimizaciones más importantes es evitar tráfico innecesariamente interregional. Si una aplicación está en una región y PostgreSQL en otra, la decisión puede aumentar tanto la latencia como los costes de transferencia.

Desde una perspectiva FinOps, el diseño correcto consiste en colocar juntos los componentes que generan tráfico intenso, seleccionar el tamaño de Cloud SQL a partir de métricas reales y revisar periódicamente CPU, memoria, conexiones, almacenamiento, IOPS y patrones de transferencia.

FAQ: Cloud SQL PostgreSQL privado con Terraform

¿Qué diferencia hay entre Private Service Access y una VPC Peering tradicional?

Private Service Access utiliza VPC Network Peering como mecanismo subyacente para conectar la VPC del consumidor con la red de servicios administrados. En Terraform, el patrón se implementa reservando un rango con propósito VPC_PEERING y creando un google_service_networking_connection. No debe confundirse con crear manualmente un peering arbitrario entre dos VPC de aplicaciones.

¿Cómo puedo evitar que Cloud SQL PostgreSQL tenga una IP pública?

Configura ipv4_enabled = false dentro de ip_configuration y proporciona private_network con la VPC que tiene Private Service Access. La conexión de Service Networking debe existir antes de crear la instancia.

¿Puedo utilizar Cloud SQL Studio con una instancia PostgreSQL privada?

Sí. Cloud SQL Studio permite consultar y administrar Cloud SQL desde la consola de Google Cloud. Requiere permisos IAM adecuados, incluyendo roles/cloudsql.studioUser, además de autenticación de base de datos. La instancia no necesita exponerse mediante una IP pública únicamente para utilizar Cloud SQL Studio.

Sobre el Autor: Eduardo Martínez Agrelo

AI & Data Architect

Eduardo Martínez Agrelo es AI & Data Architect, especializado en arquitectura de datos, inteligencia artificial, plataformas cloud y diseño de sistemas orientados a producción. Su enfoque combina arquitectura, automatización, seguridad, FinOps y decisiones técnicas orientadas a escalabilidad y operación empresarial.

© 2026 Eduardo Martínez Agrelo · AI & Data Architect

Arquitectura de referencia: Cloud SQL PostgreSQL + Private Service Access + VPC Network Peering + Terraform.