This check flags Cloud SQL instances that have a public IP address, which exposes your database to the internet and broadens your attack surface. Fix it by switching to private IP with Private Service Access, or at minimum lock down authorized networks and require SSL.
A database with a public IP is one of the most common ways teams accidentally put their most sensitive data within reach of the open internet. Cloud SQL makes it easy to provision an instance with a public address, and that default convenience has a way of sticking around long after the testing phase is over. The sql_publicip check catches Cloud SQL instances that have a public IP assigned, so you can decide whether that exposure is intentional or just leftover.
What this check detects
The check inspects each Cloud SQL instance in your GCP project and looks at its IP configuration. If the instance has a public IPv4 address assigned (the ipConfiguration.ipv4Enabled field is set to true), the check flags it.
A public IP means the instance is reachable over the internet, subject to whatever authorized networks and SSL settings you have configured. By itself a public IP does not mean the database is wide open, but it does mean the database is no longer isolated inside your VPC. The actual exposure depends on the layers you put in front of it, and those layers are easy to get wrong.
Note: Cloud SQL supports both public IP and private IP, and an instance can have either or both. Private IP uses Private Service Access, a peered connection between your VPC and Google's service producer network, so traffic never traverses the public internet.
Why it matters
When a database has a public IP, anyone on the internet can attempt to reach it. The only things stopping them are your authorized networks list, your SSL configuration, and your database credentials. Each of those is a control that can be misconfigured.
Here are the failure modes we see in the real world:
- Authorized networks set to 0.0.0.0/0. This is depressingly common. Someone needs to connect from their laptop, opens up the whole internet to "test something," and never reverts it. Now your database is reachable by every scanner on the planet.
- SSL not enforced. Without
requireSsl, clients can connect in plaintext, and credentials plus query data can be intercepted on the wire. - Brute force and credential stuffing. A public endpoint invites automated password guessing against your
rootor application users. - Exposure of known CVEs. If a vulnerability is found in your database engine, a publicly reachable instance is exploitable far faster than one sitting behind a VPC.
The business impact is straightforward. Databases hold your most valuable data: customer records, credentials, payment information, intellectual property. A breach here is not a minor incident, it is the kind that triggers regulatory disclosure, customer churn, and a very bad week for everyone involved. Several high profile data leaks have traced back to a publicly exposed database that nobody remembered was public.
Warning: An open authorized network range is far more dangerous than the public IP itself. Always check authorizedNetworks alongside this finding. A public IP with 0.0.0.0/0 authorized is effectively an open door.
How to fix it
The best fix is to remove the public IP entirely and connect over private IP. If you genuinely need public connectivity, harden it instead. Both paths are below.
Option 1: Switch to private IP (recommended)
First, make sure Private Service Access is configured for your VPC. You need an allocated IP range and a peering connection to the Google services network.
# Allocate an IP range for Private Service Access
gcloud compute addresses create google-managed-services-default \
--global \
--purpose=VPC_PEERING \
--prefix-length=16 \
--network=default
# Create the private connection to Google services
gcloud services vpc-peerings connect \
--service=servicenetworking.googleapis.com \
--ranges=google-managed-services-default \
--network=default
Then enable private IP on the instance and disable the public IP:
Warning: Removing the public IP will break any client that connects over it. Make sure your applications can reach the instance via private IP, the Cloud SQL Auth Proxy, or a VPN before you flip this. Plan a maintenance window if you are unsure.
gcloud sql instances patch INSTANCE_NAME \
--network=projects/PROJECT_ID/global/networks/default \
--no-assign-ip
The --no-assign-ip flag removes the public IPv4 address, and --network attaches the instance to your VPC for private connectivity.
Option 2: Harden the public IP (if you must keep it)
If a public IP is unavoidable, narrow the authorized networks to specific trusted ranges and require SSL.
Danger: Never set authorized networks to 0.0.0.0/0. That exposes your database to the entire internet. The command below replaces the full authorized network list, so include every range you actually need.
# Restrict access to a specific office or NAT egress range, and require SSL
gcloud sql instances patch INSTANCE_NAME \
--authorized-networks=203.0.113.10/32 \
--require-ssl
Console steps
- Open the Cloud SQL instance in the GCP Console.
- Go to Connections.
- Under Networking, uncheck Public IP and check Private IP, selecting your VPC network.
- If keeping public IP, edit Authorized networks to list only trusted CIDR ranges, and enable Allow only SSL connections.
- Click Save and wait for the instance to update.
Tip: Use the Cloud SQL Auth Proxy for application and developer access. It provides authenticated, encrypted connections through IAM without exposing a public IP or managing SSL certificates yourself, and it works over private IP too.
How to prevent it from happening again
Fixing one instance is not enough. New instances get created all the time, and the default in many provisioning flows assigns a public IP. Bake the guardrails into your platform.
Terraform: provision private by default
resource "google_sql_database_instance" "main" {
name = "app-db"
database_version = "POSTGRES_15"
region = "us-central1"
settings {
tier = "db-custom-2-7680"
ip_configuration {
ipv4_enabled = false
private_network = google_compute_network.vpc.id
require_ssl = true
}
}
deletion_protection = true
}
Setting ipv4_enabled = false means no public IP is ever assigned. Make this your module default so every team inherits it.
Organization Policy: block public IPs centrally
GCP has a built in org policy constraint that prevents Cloud SQL instances from getting a public IP at all. Apply it at the organization or folder level and you stop the problem at the source.
gcloud resource-manager org-policies enable-enforce \
sql.restrictPublicIp \
--organization=ORGANIZATION_ID
Note: The sql.restrictPublicIp constraint blocks creation of new public IP instances and prevents adding a public IP to existing ones. It does not retroactively remove public IPs from instances that already have them, so remediate those separately.
Policy as code in CI/CD
Catch the misconfiguration before it ships. Add an OPA or Conftest rule to your Terraform pipeline:
package cloudsql
deny[msg] {
resource := input.resource_changes[_]
resource.type == "google_sql_database_instance"
resource.change.after.settings[_].ip_configuration[_].ipv4_enabled == true
msg := sprintf("Cloud SQL instance '%s' must not have a public IP", [resource.address])
}
Tip: Run continuous detection with Lensix so any instance that drifts back to a public IP, whether created by hand in the console or by an exception in IaC, surfaces immediately instead of sitting undiscovered for months.
Best practices
- Default to private IP. Public connectivity should be a deliberate, reviewed exception, not the path of least resistance.
- Enforce SSL everywhere. Even on private IP, require SSL so traffic inside the VPC is encrypted.
- Use the Cloud SQL Auth Proxy or IAM database authentication. Move away from long lived passwords and toward short lived, IAM controlled credentials.
- Audit authorized networks regularly. Any range broader than a /24 deserves a second look, and
0.0.0.0/0should never appear. - Apply the org policy constraint. A preventive control at the org level beats fixing the same problem instance by instance.
- Enable Cloud SQL audit logging. Know who connected, from where, and when, so you can investigate quickly if something looks off.
- Keep deletion protection on. Unrelated to exposure, but a public database that gets compromised should not also be easy to wipe.
Removing public IPs from your databases is one of the highest leverage security improvements you can make in a GCP environment. It shrinks your attack surface dramatically and costs nothing extra. Combine the one time remediation with an org policy and a CI/CD gate, and this class of finding goes away for good.

