第 62.1 节:基于 Debian 的系统设置

(假设 MySQL 已安装,使用 sudo。)

生成 CA 和 SSL 密钥

确保已安装 OpenSSL 和库:

apt-get -y install openssl
apt-get -y install libssl-dev

接下来,创建并进入存放 SSL 文件的目录:

mkdir /home/ubuntu/mysqlcerts
cd /home/ubuntu/mysqlcerts

生成密钥,创建证书颁发机构(CA)并签名:

openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca.pem

(每个提示符下输入的值不会影响配置。)

接下来创建服务器密钥,并使用之前的 CA 签名:

openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
openssl 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.pem

然后创建客户端密钥:

openssl req -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem

验证密钥是否正确:

openssl verify -CAfile ca.pem server-cert.pem client-cert.pem

将密钥添加到 MySQL

打开 MySQL 配置文件,例如:

vim /etc/mysql/mysql.conf.d/mysqld.cnf

在 [mysqld] 部分下添加以下选项:

ssl-ca = /home/ubuntu/mysqlcerts/ca.pem
ssl-cert = /home/ubuntu/mysqlcerts/server-cert.pem
ssl-key = /home/ubuntu/mysqlcerts/server-key.pem

重启 MySQL:

service mysql restart

测试 SSL 连接

使用生成的客户端密钥,以相同方式连接,传入额外选项 ssl-ca、ssl-cert 和 ssl-key。例如,假设 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 -p

登录后,验证连接是否安全:

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_cert      | /home/ubuntu/mysqlcerts/server-cert.pem |
| ssl_key       | /home/ubuntu/mysqlcerts/server-key.pem  |
+---------------+---------------------------------+

也可以检查:

superman@127.0.0.1 [None]> STATUS;
...
SSL: Cipher in use is DHE-RSA-AES256-SHA

强制使用 SSL

通过 GRANT 语句,使用 REQUIRE SSL:

GRANT ALL PRIVILEGES ON *.* TO 'superman'@'127.0.0.1' IDENTIFIED BY 'pass' REQUIRE SSL;
FLUSH PRIVILEGES;

现在 superman 必须通过 SSL 连接。

如果你不想管理客户端密钥,可以使用之前生成的客户端密钥并自动应用于所有客户端。打开 MySQL 配置文件,例如:

vim /etc/mysql/mysql.conf.d/mysqld.conf

在 [client] 部分下添加以下选项:

ssl-ca = /home/ubuntu/mysqlcerts/ca.pem
ssl-cert = /home/ubuntu/mysqlcerts/client-cert.pem
ssl-key = /home/ubuntu/mysqlcerts/client-key.pem

现在 superman 只需输入以下命令即可通过 SSL 登录:

mysql -h 127.0.0.1 -u superman -p

从其他程序连接,例如在 Python 中,通常只需在 connect 函数中添加一个额外参数:

import MySQLdb
ssl = {'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)

参考和进一步阅读:

  • 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

第 62.2 节:CentOS7 / RHEL7 设置

(此示例假设两台服务器:dbserver 和 appclient,均启用 SELinux。)

在 dbserver 上操作

创建临时目录用于生成证书:

mkdir /root/certs/mysql/ && cd /root/certs/mysql/

创建服务器证书:

openssl genrsa 2048 > ca-key.pem
openssl req -sha1 -new -x509 -nodes -days 3650 -key ca-key.pem > ca-cert.pem
openssl req -sha1 -newkey rsa:2048 -days 730 -nodes -keyout server-key.pem > server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -sha1 -req -in server-req.pem -days 730 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem

将服务器证书移动到 /etc/pki/tls/certs/mysql/(CentOS/RHEL 路径,其他发行版酌情调整):

mkdir /etc/pki/tls/certs/mysql/
chown -R mysql:mysql /etc/pki/tls/certs/mysql/

配置 MySQL/MariaDB:

vi /etc/my.cnf

在 [mysqld] 部分添加:

[mysqld]
bind-address = *
ssl-ca = /etc/pki/tls/certs/mysql/ca-cert.pem
ssl-cert = /etc/pki/tls/certs/mysql/server-cert.pem
ssl-key = /etc/pki/tls/certs/mysql/server-key.pem

重启 MariaDB:

systemctl restart mariadb

开放防火墙以允许 appclient 连接(使用 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'
firewall-cmd --reload

登录 MySQL,创建需要 SSL 的用户:

GRANT ALL PRIVILEGES ON *.* TO 'iamsecure'@'appclient' IDENTIFIED BY 'dingdingding' REQUIRE SSL;
FLUSH PRIVILEGES;

创建客户端证书(仍在 /root/certs/mysql/ 中):

openssl req -sha1 -newkey rsa:2048 -days 730 -nodes -keyout client-key.pem > client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -sha1 -req -in client-req.pem -days 730 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem

将服务器和客户端 CA 证书合并为一个文件:

cat server-cert.pem client-cert.pem > ca.pem

在 appclient 上操作

创建客户端证书目录:

mkdir /etc/pki/tls/certs/mysql/

将客户端证书(在 dbserver 上生成)复制到 appclient(可以使用 scp 或直接复制粘贴)。

设置权限:

chown -R mysql:mysql /etc/pki/tls/certs/mysql/

应有三个文件,所有者为 mysql:

  • /etc/pki/tls/certs/mysql/ca.pem
  • /etc/pki/tls/certs/mysql/client-cert.pem
  • /etc/pki/tls/certs/mysql/client-key.pem

编辑 appclient 的 MySQL 配置,在 [client] 部分添加:

[client]
ssl-ca=/etc/pki/tls/certs/mysql/ca.pem
ssl-cert=/etc/pki/tls/certs/mysql/client-cert.pem
ssl-key=/etc/pki/tls/certs/mysql/client-key.pem

重启 MariaDB:

systemctl restart mariadb

检查 SSL 是否启用:

mysql --ssl --help

登录 appclient 的 MySQL 实例:

mysql -u root -p

执行:

SHOW VARIABLES LIKE 'have_ssl';

应显示 YES。

尝试连接到 dbserver 的 MySQL 实例:

mysql -h dbserver -u iamsecure -p

输入密码后,应能成功登录。输入 \s(状态)确认 SSL 是否启用。