Working with Cloud SQL
Working with Cloud SQL

Enforcing SSL

Published on - Updated on
Part of Working with Cloud SQL

Tutorial

In this first part of the Working with Cloud SQL series, we will see how we can secure a Cloud SQL instance by explicitly disallowing unencrypted connections. Let's first create a Cloud SQL instance that we can use for experimentation.'

Setting up the Cloud SQL instance

Navigate to the Cloud SQL dashboard in the Google Cloud Console: https://console.cloud.google.com/sql/instances

Select 'Create Instance'.

Choose 'MySQL' as the database engine.

On the page that opens provide the following details:

  1. Enter a unique instance name
  2. Enter a secure root user password for the instance
  3. Set the database version to 'MySQL 8.0'.
  4. Choose 'sandbox' as the default configuration
  5. Choose a region close to you
  6. Disable 'Deletion protection' in case you want to easily delete the instance after this tutorial

Wait for the instance creation to complete. This can take a few minutes.

Creating a Compute Engine instance for testing

Navigate to the Compute Engine dashboard: https://console.cloud.google.com/sql/instances

Select 'Create Instance'.

Enter an instance name

Choose a Region and Zone close to you

Choose the 'N1' family and then choose 'f1-micro' as the machine type

Under 'Boot disk', click 'Change'.

Choose 'Ubuntu' as the 'Operating system'.

Choose 'Ubuntu 22.04 LTS' as the 'Version'.

As boot disk type, choose 'Standard Persistent Disk'.

As disk size, select '10' GB.

Under 'Identity and API access', select 'No service account'.

Click 'Create'.

Wait for the instance creation process to complete.

Validating connectivity using an unencrypted connection

In the Compute Engine dashboard, use the 'SSH' button to open an SSH session.

Update the APT caches:

sudo apt update

Install the MySQL Client:

sudo apt install mysql-client

When prompted, confirm that you want to install the tools by entering Y and pressing ENTER.

Verify the MySQL version:

mysql --version

The output should look like this:

mysql  Ver 8.0.33 for macos13.3 on x86_64

Let's now try to connect to our Cloud SQL instance:

mysql -h <ip-address> -u root -p

When prompted enter the password of the root user.

Unfortunately, the connection hangs. Press CTRL+C to cancel the connection attempt. The reason for the connection failure is that we haven't whitelisted our Compute Engine instance's IP on our Cloud SQL instance. By default, Cloud SQL blocks internet access from all IPs.

Whitelisting the Compute Engine instance IP address in Cloud SQL

Close the SSH session for now, or minimize the window.

In the Compute Engine dashboard click on the three dots at the end of the row (see image), and select 'View network details'.

On the 'Network interface details' page, copy the 'External IP address' value.

Navigate to the Cloud SQL instance dashboard: https://console.cloud.google.com/sql/instances

Select your Cloud SQL instance.

In the sidebar, select 'Connections'.

Open the 'Networking' tab.

Under 'Authorized networks', click on 'Add a network'.

Give the network a name. (e.g. Compute Engine instance) Choose a descriptive name here, so you remember later on why you whitelisted this IP address.

In the 'Network' text field, paste the IP address you copied earlier and append /32. So the IP address should look like 123.123.123.123/32.

Click on 'Done' to confirm the whitelisting.

Click 'Save' to apply the changes to the Cloud SQL instance.

Wait a few minutes for the instance to be updated.

Validating connectivity with an unencrypted connection (attempt 2)

Reopen your SSH session to the Compute Engine instance.

Run the mysql command again to retry connectivity:

mysql -h <ip-address> -u root -p

When prompted enter the password of the root user.

We can now connect to our instance!

Depending on the MySQL client version that you are using the connection is either encrypted or unencrypted. Newer versions of the MySQL Client try to use an encrypted connection by default, but fall back to an unencrypted connection if no connection can be otherwise established. If our connection is unencrypted, a malicious actor could intercept our network traffic and potentially extract confidential information.

Let's now see how we can make sure encrypted connections are enforced by the server.

Enforcing SSL connections in our Cloud SQL instance

Navigate to the Cloud SQL instance dashboard: https://console.cloud.google.com/sql/instances

Select your Cloud SQL instance.

In the sidebar, select 'Connections'.

Open the 'Security' tab.

Under 'SSL encryption', check the 'Allow only SSL connections' flag.

A dialog shows, asking you if you want to restart the instance. Select 'Save & restart'. (Don't do this on a production instance without scheduling the downtime)

Wait a few minutes for the instance to be restarted.

Now that we've checked the 'Allow only SSL connections' flag, Google Cloud will not only enforce encrypted connections, but it will require us to authenticate with a Client Certificate in addition to the password that we already provide. This functions as a second factor of authentication and provides another layer of security for our Cloud SQL instance.

Before we can connect though, we need to generate a Client Certificate.

Click on the 'Create client certificate' button under 'Manage client certificates'.

Give the certificate a descriptive name.

Download the different certificates that are displayed. You will need all three values to connect to the instance.

Connecting to the instance using Mutual SSL

Upload the certificate files to the Compute Engine instance.

Use the certificates to establish a secure connection to the Cloud SQL instance:

mysql -h <ip-address> --ssl-ca=server-ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem --ssl-mode=VERIFY_CA -u root -p

In the above command we provide the MySQL Client with the following details:

Press ENTER to establish a connection.

We are successfully able to connect.

Finally, let's try to connect without providing all these certificates:

mysql -h <ip-address> -u root -p

As expected, MySQL is denying us access to the instance.