Skip to main content

GCP SQL No Private Ip Remediation

Triage and Remediation

Remediation

Using Console

To allow public (external) access to a Cloud SQL for PostgreSQL instance in GCP using the Console, you need to add a public IP (you can keep the private IP as well if needed).

Step-by-step in GCP Console

  1. Go to Cloud SQL

    • In the Google Cloud Console, go to:
      Navigation menu → Databases → SQL
    • Click on your PostgreSQL instance.
  2. Open the Connections settings

    • In the instance page, click the Edit button at the top.
    • In the left or central tabs, find and click Connections.
  3. Enable Public IP

    • Scroll to the Connectivity or IP addresses section.
    • Under Public IP, check Assign a public IP address (or Add network / Add public IP depending on UI version).
    • The Console will show that a public IP will be assigned on save.
  4. Configure Authorized Networks (Firewall for DB)

    • Still under Public IP, find Authorized networks.
    • Click Add Network.
    • Enter:
      • Name: A label for the client/network (e.g., office-network or dev-laptop).
      • Network: The IP or CIDR that should be allowed (e.g., 203.0.113.10/32 for a single IP).
    • Repeat for all client IPs that need access.
    • Avoid 0.0.0.0/0 unless this is a controlled test environment and you fully understand the risk.
  5. Save changes

    • Scroll down and click Save.
    • Wait for the instance to finish updating (status changes back to RUNNABLE).
  6. Get the public IP and connect

    • In the instance Overview page, under Connect to this instance or Instance IP addresses, note the Public IP address.
    • Use this host in your PostgreSQL client connection string:
      • Host: the public IP
      • Port: default 5432 unless you changed it
      • User/password / database as configured.
  7. (Optional) Keep or remove Private IP

    • If you no longer want private-only access:
      • Go back to Edit → Connections.
      • Under Private IP, uncheck / remove private IP assignment (if your design allows).
      • Save again.

This remediates the configuration from “private-only” to “private + public” (or public-only) access using the GCP Console.

Using CLI

To remediate “PostgreSQL Instance IP Assignment Set To Private” in GCP (i.e., enable a public IPv4 address) via gcloud, do the following:


1. Make sure you have the right project and auth

# Authenticate
gcloud auth login

# Set the correct project
gcloud config set project YOUR_PROJECT_ID

2. Check current IP configuration of the instance

gcloud sql instances describe INSTANCE_NAME \
--format="get(ipAddresses)"

Confirm it only has PRIVATE and no PRIMARY / PUBLIC IPv4.


Decide which client IPs should be allowed to connect to the public IP.

Example: allow only one office IP and one VPN IP:

AUTHORIZED_NETWORKS="Office=203.0.113.5/32,VPN=198.51.100.10/32"

4. Enable public IPv4 on the instance

Use gcloud sql instances patch with --assign-ip. You can optionally add authorized networks at the same time.

gcloud sql instances patch INSTANCE_NAME \
--assign-ip \
--authorized-networks="${AUTHORIZED_NETWORKS}"

Notes:

  • --assign-ip adds a public IPv4 address (keeps private IP if already enabled).
  • If you don’t want to set authorized networks now, just omit the flag and add them later.

5. Verify that a public IP was assigned

gcloud sql instances describe INSTANCE_NAME \
--format="json(ipAddresses)"

You should now see an entry like:

"ipAddresses": [
{
"type": "PRIMARY",
"ipAddress": "X.X.X.X"
},
{
"type": "PRIVATE",
"ipAddress": "10.x.x.x"
}
]

6. (Optional) Adjust or add authorized networks later

To update the allowed IP ranges:

gcloud sql instances patch INSTANCE_NAME \
--authorized-networks="Office=203.0.113.5/32,VPN=198.51.100.10/32,Home=203.0.113.20/32"

This overwrites the existing list with the one you provide.


These commands will change the instance from “private-only” to having a public IPv4 endpoint while retaining the private IP if it was already configured.

Using Python

Below is how to change a Cloud SQL for PostgreSQL instance so it has a public IP (in addition to or instead of private IP) using Python.


1. Prerequisites

  1. Cloud SQL Admin API must be enabled:

  2. Authentication:

    • Use a service account with the roles/cloudsql.admin role.
    • Set GOOGLE_APPLICATION_CREDENTIALS to point to its JSON key, or run this from an environment with default credentials (e.g., Cloud Shell, Cloud Run with attached service account).
  3. Install libraries:

pip install google-api-python-client google-auth google-auth-httplib2

2. Python code to add a public IP

This example:

  • Adds a public IP to an existing PostgreSQL instance.
  • Keeps existing private IP settings intact (if any).
  • Optionally restricts access with authorizedNetworks.

Replace:

  • PROJECT_ID with your project ID
  • INSTANCE_NAME with your Cloud SQL instance name
  • NETWORK_CIDR with your allowed CIDR (or remove authorizedNetworks block if not needed)
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google.oauth2 import service_account
import time

# ---- CONFIGURE THESE ----
PROJECT_ID = "your-gcp-project-id"
INSTANCE_NAME = "your-postgres-instance-name"
SERVICE_ACCOUNT_KEY = "path/to/service-account.json" # or use default creds
NETWORK_CIDR = "203.0.113.0/24" # example; change to your IP/CIDR
# -------------------------

def wait_for_operation(service, project, operation_name):
while True:
op = service.operations().get(
project=project,
operation=operation_name
).execute()

if op.get("status") == "DONE":
if "error" in op:
raise RuntimeError(f"Operation error: {op['error']}")
break
time.sleep(5)


def main():
# Use service account; or use google.auth.default() if running on GCP
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_KEY,
scopes=["https://www.googleapis.com/auth/cloud-platform"],
)

service = build("sqladmin", "v1beta4", credentials=creds, cache_discovery=False)

try:
# Get current instance config
instance = service.instances().get(
project=PROJECT_ID,
instance=INSTANCE_NAME
).execute()

settings = instance.get("settings", {})
ip_config = settings.get("ipConfiguration", {})

# Ensure public IP is enabled
ip_config["ipv4Enabled"] = True

# OPTIONAL: restrict access with authorized networks
# If you already have authorizedNetworks, append instead of overwrite.
ip_config["authorizedNetworks"] = [
{
"name": "allowed-office-network",
"value": NETWORK_CIDR,
}
]

settings["ipConfiguration"] = ip_config

body = {
"settings": settings
}

# Patch instance
op = service.instances().patch(
project=PROJECT_ID,
instance=INSTANCE_NAME,
body=body
).execute()

print(f"Patch operation started: {op['name']}")
wait_for_operation(service, PROJECT_ID, op["name"])
print("Instance updated. Public IP should now be assigned/enabled.")

except HttpError as e:
print(f"API error: {e}")
except Exception as e:
print(f"Error: {e}")


if __name__ == "__main__":
main()

3. Notes / Variations

  • Keep both private and public IP:
    The code above leaves any existing privateNetwork and pscConfig untouched; it just enables ipv4Enabled. That gives you dual (private + public) connectivity.

  • Remove public IP later (if needed): Set ip_config["ipv4Enabled"] = False and patch again.

  • No network restriction: If you omit authorizedNetworks, any IP can attempt to connect (still needs DB auth). For better security, always define authorizedNetworks.

This is the standard remediation path if your security policy requires a publicly reachable PostgreSQL Cloud SQL instance instead of only private IP.

Using Terraform
resource "google_sql_database_instance" "POSTGRES_INSTANCE" {
name = "POSTGRES_INSTANCE_NAME" # replace with your instance name
database_version = "POSTGRES_14" # replace with your required version
region = "GCP_REGION" # replace with the region (e.g. us-central1)

settings {
tier = "DB_TIER" # e.g. db-custom-2-7680

ip_configuration {
# Disable public IP
ipv4_enabled = false

# Attach to a VPC for private IP
private_network = google_compute_network.VPC.self_link
# or use: "projects/PROJECT_ID/global/networks/VPC_NETWORK_NAME"
}
}
}

resource "google_compute_network" "VPC" {
name = "VPC_NETWORK_NAME" # replace or reference existing VPC
}

resource "google_compute_global_address" "SQL_PRIVATE_SERVICE_RANGE" {
name = "SQL_PRIVATE_SERVICE_RANGE_NAME" # replace with a unique name
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = google_compute_network.VPC.id
}

resource "google_service_networking_connection" "SQL_VPC_PEERING" {
network = google_compute_network.VPC.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.SQL_PRIVATE_SERVICE_RANGE.name]
}

Changing an existing Cloud SQL instance from public IP to private IP (private_network plus ipv4_enabled = false) can force replacement of the instance, which may cause downtime; review the terraform plan carefully before applying.

For verification, terraform plan should show the google_sql_database_instance gaining settings.ip_configuration.private_network and ipv4_enabled = false, and (for an existing public-only instance) it may show the instance being replaced along with creation of the networking/peering resources if they are new.