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
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
-
Go to Cloud SQL
- In the Google Cloud Console, go to:
Navigation menu → Databases → SQL - Click on your PostgreSQL instance.
- In the Google Cloud Console, go to:
-
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.
-
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.
-
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-networkordev-laptop). - Network: The IP or CIDR that should be allowed (e.g.,
203.0.113.10/32for a single IP).
- Name: A label for the client/network (e.g.,
- Repeat for all client IPs that need access.
- Avoid
0.0.0.0/0unless this is a controlled test environment and you fully understand the risk.
-
Save changes
- Scroll down and click Save.
- Wait for the instance to finish updating (status changes back to RUNNABLE).
-
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
5432unless you changed it - User/password / database as configured.
-
(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.
- If you no longer want private-only access:
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.
3. (Optional but recommended) Define authorized networks
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-ipadds 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
-
Cloud SQL Admin API must be enabled:
-
Authentication:
- Use a service account with the
roles/cloudsql.adminrole. - Set
GOOGLE_APPLICATION_CREDENTIALSto point to its JSON key, or run this from an environment with default credentials (e.g., Cloud Shell, Cloud Run with attached service account).
- Use a service account with the
-
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_IDwith your project IDINSTANCE_NAMEwith your Cloud SQL instance nameNETWORK_CIDRwith your allowed CIDR (or removeauthorizedNetworksblock 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 existingprivateNetworkandpscConfiguntouched; it just enablesipv4Enabled. That gives you dual (private + public) connectivity. -
Remove public IP later (if needed): Set
ip_config["ipv4Enabled"] = Falseand patch again. -
No network restriction: If you omit
authorizedNetworks, any IP can attempt to connect (still needs DB auth). For better security, always defineauthorizedNetworks.
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.