Skip to main content

PostgreSQL Instance IP Assignment Set To Private

More Info:​

Instance addresses can be public IP or private IP. Public IP means that the instance isaccessible through the public internet. In contrast, instances using only private IP arenot accessible through the public internet, but are accessible through a Virtual PrivateCloud

Risk Level​

Medium

Address​

Reliability, Security

Compliance Standards​

  • CIS GCP
  • CIS GCP 2.0.0

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.

Additional Reading:​