RDS (MySQL) over SSL

The AWS-service RDS (Relational Database Service) offers fully managed relational databases as a service. The database-types can be MySQL, PostgreSQL, MariaDB, Oracle, Mircosoft SQL-Server or Amazon Aurora. In case you never heard of Amazon Aurora, it’s a database with MySQL under the hood with lots of improvements concerning performance, scalability and failover-concepts.

Unfortunately, Amazon Aurora isn’t available in my home region (eu-central-1 / Frankfurt, Germany), yet. Therefore, we’re using MySQL over a SSL-encrypted connection.

Check if SSL is SSL enable on the server

In case you want to check if your MySQL-server supports SSL-encrypted connections, connect to the database and issue the command show variables like ‘%ssl’;.

mysql> SHOW variables like '%ssl';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_openssl  | YES   |
| have_ssl      | YES   |
+---------------+-------+
2 rows in set (0.00 sec)

Your output should tell you now have_openssl=YES and have_ssl=YES.

Using SSL

Download SSL-certificates

Before we can connect to our MySQL-instance via SSL, a SSL-pem bundle is needed. The bundle needs to contain the region’s specific intermediate, as well as the root-ca’s certificate. To help you with getting the needed certificate-bundle, I wrote a small Bash-script. It takes only one parameter, which is the region.

#!/bin/bash

# parameters
region=$1

# variabales
intermediate_file="rds-ca-2015-${region}.pem"
intermediate_url="https://s3.amazonaws.com/rds-downloads/${intermediate_file}"
root_file="rds-ca-2015-root.pem"
root_url="https://s3.amazonaws.com/rds-downloads/${root_file}"
bundle_file="rds-ca-2015-${region}-bundle.pem"

if [[ $region == '' ]]; then
	echo "region must be specified"
	echo "usage: rds-certificate-downloader.sh eu-central-1"
	exit 1
fi

wget -q $intermediate_url
wget -q $root_url

cat $intermediate_file > $bundle_file
rm $intermediate_file

cat $root_file >> $bundle_file
rm $root_file

Note: in this example, we will create a certificate-bundle for the region eu-central-1. Therefore, the output-filename will be rds-ca-2015-eu-central-1-bundle.pem.

Connect via SSL

You can test your connection to the MySQL-database without SSL the following way. You should already have access to the database. In case you can’t establish a connection, please check your configuration upfront.

Note: the username for this example here is db_root and the database-name is db_name. You need to adjust that to your own RDS-setup upfront.

mysql -u db_root -p -h XYZ.XXXXXXXXXXXX.eu-central-1.rds.amazonaws.com -P 3306 db_name

If everything is working as expected, you get the following output in your mysql-client.

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 29
Server version: 5.6.27-log MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

As we want to connect via a SSL-encrypted connection, use the following command for connecting.

mysql -h XYZ.XXXXXXXXXXXX.eu-central-1.rds.amazonaws.com \
	-P 3306 \
	--ssl-ca=rds-ca-2015-eu-central-1-bundle.pem \
	--ssl-verify-server-cert \
	-u db_root -p db_name

If you’re getting the same output in your mysql-client as before, you are successfully connected to your MySQL-database. To also check if your connection is encrypted, have a look at your status-output.

mysql> status;
--------------
mysql  Ver 14.14 Distrib 5.6.28, for debian-linux-gnu (x86_64) using  EditLine wrapper

Connection id:		33
Current database:	db_name
Current user:		db_root@XXX.XXX.XXX.XXX
SSL:			Cipher in use is AES256-SHA
Current pager:		stdout
Using outfile:		''
Using delimiter:	;
Server version:		5.6.27-log MySQL Community Server (GPL)
Protocol version:	10
Connection:		XYZ.XXXXXXXXXXXX.eu-central-1.rds.amazonaws.com via TCP/IP
Server characterset:	latin1
Db     characterset:	latin1
Client characterset:	utf8
Conn.  characterset:	utf8
TCP port:		3306
Uptime:			38 min 9 sec

Threads: 2  Questions: 11222  Slow queries: 0  Opens: 355  Flush tables: 1  Open tables: 67  Queries per second avg: 4.902
--------------

In the SSL-variable from the output, you should now depending on your SSL-cipher see anything different to SSL: Not in use.

Enforcing SSL

When designing new services, AWS always has a strict and sensible security-concept in mind, which is a good way of improving overall application-security. However, for RDS (MySQL), AWS decided for the default-configuration to only enable SSL-encrypted connections, but is not enforcing its usage.

In order to enforce SSL-encrypted connections, connect to your database in an ordinary manner and issue the follwing command. Afterwards connections to the database for the specified user need to be over an SSL-encrypted connection.

Note: the username for this example here is db_root. You need to adjust that username to your RDS-setup.

Keep your current connection to the database open and check it with a second session! If anything goes wrong, you then can still revert your changes.

mysql> UPDATE mysql.user SET ssl_type='ANY' WHERE user='db_root';
mysql> FLUSH PRIVILEGES;



Written on 2016-04-24