# GCP Cloud SQL Instance Does Not Require SSL

> Flags Cloud SQL instances that do not require SSL/TLS, so clients can still connect in plaintext.

Source: https://zop.dev/integrations/gcp/recommendations/gcp-cloud-sql-instance-does-not-require-ssl

---

## What the default SSL mode allows

Cloud SQL offers three SSL enforcement modes. The
[SSL configuration guide](https://cloud.google.com/sql/docs/mysql/configure-ssl-instance) lists
`ALLOW_UNENCRYPTED_AND_ENCRYPTED` as the default, which accepts both plaintext and TLS
connections and does not verify client certificates. `ENCRYPTED_ONLY` accepts only TLS, and
`TRUSTED_CLIENT_CERTIFICATE_REQUIRED` accepts only TLS with a valid client certificate.

So an instance nobody configured will take a plaintext connection from any client that asks for
one. On a private network that is still traffic other workloads may be able to observe; on a
public IP, Google says it strongly recommends enforcing SSL for all connections. Clients that use
the Cloud SQL Auth Proxy or the Cloud SQL Connectors are encrypted regardless of the mode, which is
why enforcing TLS rarely breaks well-configured applications.

## Checking the SSL setting on each instance

```bash
gcloud sql instances list \
  --format="table(name, databaseVersion, settings.ipConfiguration.sslMode, settings.ipConfiguration.requireSsl)"
```

Google recommends using SSL mode instead of the legacy `require-ssl` parameter, and warns that the
two should not conflict, so check both columns.

## The gate ZopNight applies

ZopNight confirms the resource is a genuine Cloud SQL instance by checking it has a recorded
machine tier, then reads the legacy `requireSsl` field of the instance's IP configuration. The rule
fires whenever that value is absent or anything other than true. It does not look at traffic,
certificates or which clients connect.

## When no finding appears

Resources without a recorded tier are skipped, so partial inventory records do not generate
alerts. An instance with `requireSsl` set to true is silent. The [Cloud SQL Admin API reference](https://cloud.google.com/sql/docs/mysql/admin-api/rest/v1/instances) lists the
valid pairs: on MySQL and PostgreSQL, `ENCRYPTED_ONLY` goes with `requireSsl=false` and only
`TRUSTED_CLIENT_CERTIFICATE_REQUIRED` goes with `true`; on SQL Server, `ENCRYPTED_ONLY` goes with
`true`. So a MySQL or PostgreSQL instance enforcing server-only TLS is still reported, even though
it rejects plaintext. If
the instance also has a public address, that exposure is reported separately by
<a href="https://zop.dev/integrations/gcp/recommendations/gcp-cloud-sql-instance-has-public-ip-enabled">GCP Cloud SQL Instance Has Public IP Enabled</a>.

## Exposure, not a saving

There is no cost change and ZopNight reports a $0 saving. The risk is interception: database
credentials, query text and result sets in plaintext wherever the traffic travels, and an easy
audit failure under most compliance frameworks.

## Enforcing encrypted connections

1. Find clients that connect without TLS. Moving them to the Cloud SQL Auth Proxy or a Cloud SQL
   Connector is the least effort path, since those encrypt automatically.
2. For direct clients, download the server CA certificate and set the client option, for example
   `ssl-mode=REQUIRED` for MySQL clients or `sslmode=require` for PostgreSQL.
3. Enforce it on the instance:

   ```bash
   gcloud sql instances patch INSTANCE_NAME --ssl-mode=ENCRYPTED_ONLY
   ```

   This blocks plaintext. On MySQL and PostgreSQL the finding only clears with
   `TRUSTED_CLIENT_CERTIFICATE_REQUIRED` (mutual TLS), since that is the mode Google pairs with
   `requireSsl=true`; if you settle on `ENCRYPTED_ONLY`, record the finding as accepted.
4. Test every application connection. Plaintext clients will fail from this point on.

**Warning**
Google notes that enforcing SSL restarts the instance, and the restart can cause downtime. Schedule it.
