Cloud SQL instances that accept non-SSL connections
What does ZopNight detect here?
A Cloud SQL instance that does not set requireSsl accepts unencrypted client connections, exposing credentials and query traffic on the network path. ZopNight rule RC-137 fires when the discoverer finds no SSL-enforcement marker on an enriched instance, inferred from absence and gated on the always-present tier field. Severity is high, saving $0.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-137 |
| Category | compliance |
| Severity | high |
| Metric | none — pure configuration read |
| Source | cloudsql_ssl.go |
Where it applies
Plaintext between app and database
When settings.ipConfiguration.requireSsl is unset, a Cloud SQL instance will happily
accept a client that never negotiates TLS. Every such connection carries the database
password in the authentication handshake and the query results in the clear, readable by
anything positioned on the network path. Individual clients may still connect encrypted,
since the setting governs what the server tolerates rather than what clients do. That is
exactly the problem: one misconfigured connection string anywhere in the fleet silently downgrades to
plaintext and nothing complains.
requireSsl and the marker ZopNight looks for
Detection is inferred from absence, with a guard that keeps the inference honest. The
discoverer enriches every Cloud SQL instance from its settings proto and writes an
SSL-enforcement marker only when requireSsl is actually set. The marker has no false
form. The rule first requires the tier metadata field, which the enricher stamps from
settings.tier on every genuine Cloud SQL instance; if that anchor is missing, the resource
was never enriched and the rule abstains. Only an enriched instance lacking the SSL marker
produces the finding. Reads run under roles/cloudsql.viewer (cloudsql.instances.list)
with discovery under roles/cloudasset.viewer.
Private IP does not excuse it
A tempting dismissal is “the instance is private, interception is moot.” The rule fires on private-IP instances deliberately. VPC-internal traffic is only as trustworthy as the least compromised workload inside the VPC. After an initial foothold, lateral movement puts an attacker on the same network path the plaintext crosses. Encryption in transit is the control that stays standing when the network boundary has already failed.
Confirm enforcement on one instance
gcloud sql instances describe INSTANCE_NAME \ --format="value(settings.ipConfiguration.requireSsl)"Anything other than True reproduces the finding for that instance.
Rolling out enforcement without an outage
Flipping enforcement before clients are ready is a self-inflicted outage, so sequence it:
download the server CA certificate, update connection strings (ssl-mode=REQUIRED for
MySQL, sslmode=require for PostgreSQL) and verify every application connects encrypted
while the server still permits both. Only then set the instance to require SSL (or trusted
client certificates for mutual TLS). Done in that order, the change is a non-event; done in
the other order, it is a hard cutoff for every non-TLS client at once.