SSL Connection Setup
Setup for Debian-based systems
Section titled “Setup for Debian-based systems”(This assumes MySQL has been installed and that sudo is being used.)
Generating a CA and SSL keys
Section titled “Generating a CA and SSL keys”Make sure OpenSSL and libraries are installed:
apt-get -y install opensslapt-get -y install libssl-devNext make and enter a directory for the SSL files:
mkdir /home/ubuntu/mysqlcertscd /home/ubuntu/mysqlcertsTo generate keys, create a certificate authority (CA) to sign the keys (self-signed):
openssl genrsa 2048 > ca-key.pemopenssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca.pemThe values entered at each prompt won’t affect the configuration. Next create a key for the server, and sign using the CA from before:
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pemopenssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pemThen create a key for a client:
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pemopenssl rsa -in client-key.pem -out client-key.pemopenssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pemTo make sure everything was set up correctly, verify the keys:
openssl verify -CAfile ca.pem server-cert.pem client-cert.pemAdding the keys to MySQL
Section titled “Adding the keys to MySQL”Open the MySQL configuration file. For example:
vim /etc/mysql/mysql.conf.d/mysqld.cnfUnder the [mysqld] section, add the following options:
ssl-ca = /home/ubuntu/mysqlcerts/ca.pemssl-cert = /home/ubuntu/mysqlcerts/server-cert.pemssl-key = /home/ubuntu/mysqlcerts/server-key.pemRestart MySQL. For example:
service mysql restartTest the SSL connection
Section titled “Test the SSL connection”Connect in the same way, passing in the extra options ssl-ca, ssl-cert, and ssl-key, using the generated client key. For example, assuming cd /home/ubuntu/mysqlcerts:
mysql --ssl-ca=ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem -h 127.0.0.1 -u superman -pAfter logging in, verify the connection is indeed secure:
superman@127.0.0.1 [None]> SHOW VARIABLES LIKE '%ssl%';+---------------+-----------------------------------------+| Variable_name | Value |+---------------+-----------------------------------------+| have_openssl | YES || have_ssl | YES || ssl_ca | /home/ubuntu/mysqlcerts/ca.pem || ssl_capath | || ssl_cert | /home/ubuntu/mysqlcerts/server-cert.pem || ssl_cipher | || ssl_crl | || ssl_crlpath | || ssl_key | /home/ubuntu/mysqlcerts/server-key.pem |+---------------+-----------------------------------------+You could also check:
superman@127.0.0.1 [None]> STATUS;...SSL: Cipher in use is DHE-RSA-AES256-SHA...Enforcing SSL
Section titled “Enforcing SSL”This is via GRANT, using REQUIRE SSL:
GRANT ALL PRIVILEGES ON *.* TO 'superman'@'127.0.0.1' IDENTIFIED BY 'pass' REQUIRE SSL;FLUSH PRIVILEGES;Now, superman must connect via SSL.
If you don’t want to manage client keys, use the client key from earlier and automatically use that for all clients. Open MySQL configuration file, for example:
vim /etc/mysql/mysql.conf.d/mysqld.cnfUnder the [client] section, add the following options:
ssl-ca = /home/ubuntu/mysqlcerts/ca.pemssl-cert = /home/ubuntu/mysqlcerts/client-cert.pemssl-key = /home/ubuntu/mysqlcerts/client-key.pemNow superman only has to type the following to login via SSL:
mysql -h 127.0.0.1 -u superman -pConnecting from another program, for example in Python, typically only requires an additional parameter to the connect function. A Python example:
import MySQLdbssl = {'cert': '/home/ubuntu/mysqlcerts/client-cert.pem', 'key': '/home/ubuntu/mysqlcerts/client-key.pem'}conn = MySQLdb.connect(host='127.0.0.1', user='superman', passwd='imsoawesome', ssl=ssl)References and further reading:
Section titled “References and further reading:”- https://www.percona.com/blog/2013/06/22/setting-up-mysql-ssl-and-secure-connections/
- https://lowendbox.com/blog/getting-started-with-mysql-over-ssl/
- http://xmodulo.com/enable-ssl-mysql-server-client.html
- https://ubuntuforums.org/showthread.php?t=1121458
Setup for CentOS7 / RHEL7
Section titled “Setup for CentOS7 / RHEL7”This example assumes two servers:
- dbserver (where our database lives)
- appclient (where our applications live)
FWIW, both servers are SELinux enforcing.
First, log on to dbserver
Section titled “First, log on to dbserver”Create a temporary directory for creating the certificates.
mkdir /root/certs/mysql/ && cd /root/certs/mysql/Create the server certificates
openssl genrsa 2048 > ca-key.pemopenssl req -sha1 -new -x509 -nodes -days 3650 -key ca-key.pem > ca-cert.pemopenssl req -sha1 -newkey rsa:2048 -days 730 -nodes -keyout server-key.pem > server-req.pemopenssl rsa -in server-key.pem -out server-key.pemopenssl x509 -sha1 -req -in server-req.pem -days 730 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pemMove server certificates to /etc/pki/tls/certs/mysql/
Directory path assumes CentOS or RHEL (adjust as needed for other distros):
mkdir /etc/pki/tls/certs/mysql/Be sure to set permissions on the folder and files. mysql needs full ownership and access.
chown -R mysql:mysql /etc/pki/tls/certs/mysqlNow configure MySQL/MariaDB
# vi /etc/my.cnf# i[mysqld]bind-address=*ssl-ca=/etc/pki/tls/certs/ca-cert.pemssl-cert=/etc/pki/tls/certs/server-cert.pemssl-key=/etc/pki/tls/certs/server-key.pem# :wqThen
systemctl restart mariadbDon’t forget to open your firewall to allow connections from appclient (using IP 1.2.3.4)
firewall-cmd --zone=drop --permanent --add-rich-rule 'rule family="ipv4" source address="1.2.3.4" service name="mysql" accept'# I force everything to the drop zone. Season the above command to taste.Now restart firewalld
service firewalld restartNext, log in to dbserver’s mysql server:
mysql -uroot -pIssue the following to create a user for the client. note REQUIRE SSL in GRANT statement.
GRANT ALL PRIVILEGES ON *.* TO ‘iamsecure’@’appclient’ IDENTIFIED BY ‘dingdingding’ REQUIRE SSL;FLUSH PRIVILEGES;# quit mysqlYou should still be in /root/certs/mysql from the first step. If not, cd back to it for one of the commands below.
Create the client certificates
openssl req -sha1 -newkey rsa:2048 -days 730 -nodes -keyout client-key.pem > client-req.pemopenssl rsa -in client-key.pem -out client-key.pemopenssl x509 -sha1 -req -in client-req.pem -days 730 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pemNote: I used the same common name for both server and client certificates. YMMV.
Be sure you’re still /root/certs/mysql/ for this next command
Combine server and client CA certificate into a single file:
cat server-cert.pem client-cert.pem > ca.pemMake sure you see two certificates:
cat ca.pemEND OF SERVER SIDE WORK FOR NOW.
Section titled “END OF SERVER SIDE WORK FOR NOW.”Open another terminal and
ssh appclientAs before, create a permanent home for the client certificates
mkdir /etc/pki/tls/certs/mysql/Now, place the client certificates (created on dbserver) on appclient. You can either scp them over, or just copy and paste the files one by one.
scp dbserver# copy files from dbserver to appclient# exit scpAgain, be sure to set permissions on the folder and files. mysql needs full ownership and access.
chown -R mysql:mysql /etc/pki/tls/certs/mysqlYou should have three files, each owned by user mysql:
/etc/pki/tls/certs/mysql/ca.pem/etc/pki/tls/certs/mysql/client-cert.pem/etc/pki/tls/certs/mysql/client-key.pemNow edit appclient’s MariaDB/MySQL config in the [client] section.
vi /etc/my.cnf# i[client]ssl-ca=/etc/pki/tls/certs/mysql/ca.pemssl-cert=/etc/pki/tls/certs/mysql/client-cert.pemssl-key=/etc/pki/tls/certs/mysql/client-key.pem# :wqRestart appclient’s mariadb service:
systemctl restart mariadbstill on the client here
Section titled “still on the client here”This should return: ssl TRUE
mysql --ssl --helpNow, log in to appclient’s mysql instance
mysql -uroot -pShould see YES to both variables below
show variables LIKE '%ssl'; have_openssl YES have_ssl YESInitially I saw
have_openssl NOA quick look into mariadb.log revealed:
SSL error: Unable to get certificate from '/etc/pki/tls/certs/mysql/client-cert.pem'
The problem was that root owned client-cert.pem and the containing folder. The solution was to set ownership of /etc/pki/tls/certs/mysql/ to mysql.
chown -R mysql:mysql /etc/pki/tls/certs/mysqlRestart mariadb if needed from the step immediately above
NOW WE ARE READY TO TEST THE SECURE CONNECTION
Section titled “NOW WE ARE READY TO TEST THE SECURE CONNECTION”We’re still on appclient here
Section titled “We’re still on appclient here”Attempt to connect to dbserver’s mysql instance using the account created above.
mysql -h dbserver -u iamsecure -p# enter password dingdingding (hopefully you changed that to something else)With a little luck you should be logged in without error.
To confirm you are connected with SSL enabled, issue the following command from the MariaDB/MySQL prompt:
\sThat’s a backslash s, aka status
That will show the status of your connection, which should look something like this:
Connection id: 4Current database:Current user: iamsecure@appclientSSL: Cipher in use is DHE-RSA-AES256-GCM-SHA384Current pager: stdoutUsing outfile: ''Using delimiter: ;Server: MariaDBServer version: 5.X.X-MariaDB MariaDB ServerProtocol version: 10Connection: dbserver via TCP/IPServer characterset: latin1Db characterset: latin1Client characterset: utf8Conn. characterset: utf8TCP port: 3306Uptime: 42 min 13 secIf you get permission denied errors on your connection attempt, check your GRANT statement above to make sure there aren’t any stray characters or ’ marks.
If you have SSL errors, go back through this guide to make sure the steps are orderly.
This worked on RHEL7 and will likely work on CentOS7, too. Cannot confirm whether these exact steps will work elsewhere.
Hope this saves someone else a little time and aggravation.