[TOC] # 1.检查当前SSL / TLS状态 我们将使用-h指定IPv4本地环回接口,以强制客户端与TCP连接,而不是使用本地套接字文件。 这将允许我们检查TCP连接的SSL状态: ```SHELL mysql -u root -p -h 127.0.0.1 ``` 键入以下内容以显示SSL / TLS变量的状态: ```SQL SHOW VARIABLES LIKE '%ssl%'; ``` ``` Output +---------------+----------+ | Variable_name | Value | +---------------+----------+ | have_openssl | DISABLED | | have_ssl | DISABLED | | ssl_ca | | | ssl_capath | | | ssl_cert | | | ssl_cipher | | | ssl_crl | | | ssl_crlpath | | | ssl_key | | +---------------+----------+ 9 rows in set (0.01 sec) ``` have_openssl和have_ssl字段显示DISABLE,表示当前mysql拥有ssl的功能,但是ssl功能未默认启动。 检查我们当前连接的状态以确认: ```Sql \s ``` ``` Output -------------- mysql Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using EditLine wrapper Connection id: 30 Current database: Current user: root@localhost SSL: Not in use Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.7.17-0ubuntu0.16.04.1 (Ubuntu) Protocol version: 10 Connection: 127.0.0.1 via TCP/IP Server characterset: latin1 Db characterset: latin1 Client characterset: utf8 Conn. characterset: utf8 TCP port: 3306 Uptime: 3 hours 38 min 44 sec Threads: 1 Questions: 70 Slow queries: 0 Opens: 121 Flush tables: 1 Open tables: 40 Queries per second avg: 0.005 -------------- ``` 上面显示的`SSL: Not in use`说明,当前连接没有在SSL安全连接中 关闭当前MySQL会话: ```SHELL exit ``` # 2.生成SSL / TLS证书和密钥 要启用到MySQL的SSL连接,我们首先需要生成相应的证书和密钥文件。 MySQL 5.7及更高版本提供了一个名为`mysql_ssl_rsa_setup`的实用程序,我们使用root权限生成相关的请求文件和证书对,为了能让`mysql`有权限去使用,命令中应该使用选项和参数`--uid=mysql`来指定uid。 ```SHELL sudo mysql_ssl_rsa_setup --uid=mysql ``` 命令执行生成证书的过程如下: ``` root@simon-pc:/home/simon# mysql_ssl_rsa_setup --uid=mysql Generating a 2048 bit RSA private key ...........+++ .................................................................................+++ writing new private key to 'ca-key.pem' ----- Generating a 2048 bit RSA private key .+++ ....................................................................+++ writing new private key to 'server-key.pem' ----- Generating a 2048 bit RSA private key ...................................................+++ ...............+++ writing new private key to 'client-key.pem' ----- root@simon-pc:/home/simon# ``` 检查生成的文件: ```shell root@simon-pc:/home/simon# sudo find /var/lib/mysql -name '*.pem' -ls 655857 4 -rw------- 1 mysql mysql 1679 Feb 1 09:36 /var/lib/mysql/ca-key.pem 657410 4 -rw------- 1 mysql mysql 1679 Feb 1 09:36 /var/lib/mysql/server-key.pem 657421 4 -rw-r--r-- 1 mysql mysql 1107 Feb 1 09:36 /var/lib/mysql/server-cert.pem 655989 4 -rw-r--r-- 1 mysql mysql 1107 Feb 1 09:36 /var/lib/mysql/ca.pem 657461 4 -rw-r--r-- 1 mysql mysql 1107 Feb 1 09:36 /var/lib/mysql/client-cert.pem 657426 4 -rw------- 1 mysql mysql 1679 Feb 1 09:36 /var/lib/mysql/client-key.pem 653150 4 -rw------- 1 mysql mysql 1675 Feb 1 09:36 /var/lib/mysql/private_key.pem 655778 4 -rw-r--r-- 1 mysql mysql 451 Feb 1 09:36 /var/lib/mysql/public_key.pem root@simon-pc:/home/simon# ``` 这些文件是证书颁发机构(以“ca”开头),MySQL服务器进程(以“服务器”开头)和MySQL客户端(以“客户端”开头)的密钥和证书对。 此外,当不使用SSL时,MySQL使用private_key.pem和public_key.pem文件来安全地传输密码。 # 3.在MySQL服务器上启用SSL连接 现在新版本的MySQL将在服务器启动时在MySQL数据目录中查找相应的证书文件。 因此,我们实际上不需要修改MySQL配置来启用SSL,重启即可。 ```SHELL sudo systemctl restart mysql ``` 连接MySql,MySQL客户端将自动尝试使用SSL进行连接: ```SHELL mysql -u root -p -h 127.0.0.1 ``` 检查SSL相关变量的值: ```Sql SHOW VARIABLES LIKE '%ssl%'; ``` ``` +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | have_openssl | YES | | have_ssl | YES | | ssl_ca | ca.pem | | ssl_capath | | | ssl_cert | server-cert.pem | | ssl_cipher | | | ssl_crl | | | ssl_crlpath | | | ssl_key | server-key.pem | +---------------+-----------------+ 9 rows in set (0.00 sec) ``` 上面显示说明正确启动了SSL功能。 再次检查连接详细信息: ```sql \s ``` ``` -------------- mysql Ver 14.14 Distrib 5.7.21, for Linux (x86_64) using EditLine wrapper Connection id: 5 Current database: Current user: root@localhost SSL: Cipher in use is DHE-RSA-AES256-SHA Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.7.21-0ubuntu0.16.04.1 (Ubuntu) Protocol version: 10 Connection: 127.0.0.1 via TCP/IP Server characterset: latin1 Db characterset: latin1 Client characterset: utf8 Conn. characterset: utf8 TCP port: 3306 Uptime: 31 min 54 sec Threads: 1 Questions: 10 Slow queries: 0 Opens: 107 Flush tables: 1 Open tables: 26 Queries per second avg: 0.005 -------------- ``` 上面显示的`SSL: Cipher in use is DHE-RSA-AES256-SHA`说明我们正在使用SSL。 # 4.为远程客户端配置安全连接 现在我们已在服务器上提供SSL,我们可以开始配置安全远程访问。 为此,我们需要: - 需要SSL用于远程连接 - 绑定到公共接口 - 为远程连接创建MySQL用户 - 调整我们的防火墙规则以允许外部连接 ## 4.1使用强制SSL配置远程访问 目前,MySQL服务器配置为接受来自客户端的SSL连接。 但是,如果客户端请求,它仍然允许未加密的连接。 我们可以通过打开`require_secure_transport`选项来解决这个问题。 这需要所有连接都使用`SSL`或本地`Unix`套接字。 由于只能从服务器本身访问`Unix`套接字,因此对远程用户开放的唯一连接选项将使用`SSL`。 要启用此设置,请在文本编辑器中打开`/etc/mysql/my.cnf`文件: ```shell sudo nano /etc/mysql/my.cnf ``` 在里面,会有两个`!includedir`指令用于源额外的配置文件。 我们需要在这些行下面放置我们自己的配置,以便覆盖任何冲突的设置。 首先创建一个`[mysqld]`节来定位`MySQL`服务器进程。 在该节标题下,将`require_secure_transport`设置为`ON `,: ```shell . . . !includedir /etc/mysql/conf.d/ !includedir /etc/mysql/mysql.conf.d/ [mysqld] # Require clients to connect either using SSL # or through a local socket file require_secure_transport = ON ``` 该行是执行安全连接所需的唯一设置。 默认情况下,`MySQL`被配置为仅监听源自本地计算机的连接。 要配置它监听远程连接,我们可以将`bind-address`设置为不同的接口。 为了允许`MySQL`在其任何接口上接受连接,我们可以将`bind-address`设置为“`0.0.0.0`”: ```shell . . . !includedir /etc/mysql/conf.d/ !includedir /etc/mysql/mysql.conf.d/ [mysqld] # Require clients to connect either using SSL # or through a local socket file require_secure_transport = ON bind-address = 0.0.0.0 ``` 保存并在完成后关闭文件。 接下来,重新启动MySQL以应用新设置: ```shell sudo systemctl restart mysql ``` 验证`MySQL`是否正在监听“`0.0.0.0`”而不是“`127.0.0.1`”通过键入: ```shell sudo netstat -plunt ``` ``` Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 4330/mysqld tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1874/sshd tcp6 0 0 :::22 :::* LISTEN 1874/sshd ``` 让防火墙允许MySQL连接 ``` ufw allow mysql ``` # 5.配置远程MySQL用户 ```shell mysql -u root -p ``` 在里面,您可以使用CREATE USER命令创建一个新的远程用户。 我们将在用户规范的主机部分使用我们的客户端机器的IP地址来限制与该机器的连接。 对于将来require_secure_transport选项关闭时的一些冗余,我们还将在创建帐户期间指定此用户通过包含REQUIRE SSL子句来REQUIRE SSL : ```sql CREATE USER 'remote_user'@'mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL; ``` 接下来,授予他们应该有权访问的数据库或表的新用户权限。 为了演示,我们将创建一个example数据库,并赋予我们新的用户所有权: ```sql CREATE DATABASE example; GRANT ALL ON example.* TO 'remote_user'@'mysql_client_IP'; ``` 接下来,刷新权限以立即应用这些设置: ```sql FLUSH PRIVILEGES; exit ``` # 6.测试远程连接 `remote_user`:用户名,`mysql_server_IP`:MySql服务器所在IP地址 ```shell mysql -u remote_user -p -h mysql_server_IP ``` 检查以确保您的连接安全: ```sql \s ``` ``` Output -------------- . . . SSL: Cipher in use is DHE-RSA-AES256-SHA . . . Connection: mysql_server_IP via TCP/IP . . . ``` 上面显示当前连接在SSL保护下 ```sql exit ``` 尝试不安全的连接: ```shell mysql -u remote_user -p -h mysql_server_IP --ssl-mode=disabled ``` 即使输入正确的密码,依然后提示拒绝访问,`--ssl-mode=disabled`表示连接会话不启用SSL: ``` OutputERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_server_IP' (using password: YES) ``` # 7.配置MySQL连接验证(可选) 目前,我们的MySQL服务器配置有由本地生成的证书颁发机构(CA)签名的SSL证书。 服务器的证书和密钥对足以为传入连接提供加密。 但是,我们目前没有利用证书颁发机构可以提供的信任关系。 通过将CA证书分发给客户端以及客户端证书和密钥,双方可以提供其证书由相互信任的证书颁发机构签名的证明。 这可以帮助防止恶意服务器的欺骗性连接。 为了实施这个额外的可选保护措施,我们需要: - 将适当的SSL文件传输到客户端计算机 - 创建客户端配置文件 - 更改远程用户以要求受信任的证书 ## 7.1将客户端证书传输到客户端计算机 首先,我们需要从MySQL服务器获取MySQL CA和客户端证书文件,并将它们放在MySQL客户端上。 首先在MySQL客户端上的用户的主目录中创建一个目录,用于连接。 调用此`client-ssl` : ```shell mkdir ~/client-ssl ``` 由于证书密钥是敏感的,我们应该锁定对此目录的访问,以便只有当前用户可以访问它: ```shell chmod 700 ~/client-ssl ``` 现在,我们可以将证书信息复制到新目录。 在MySQL服务器计算机上,通过键入以下内容显示CA证书的内容: ```shell sudo cat /var/lib/mysql/ca.pem ``` ``` -----BEGIN CERTIFICATE----- . . . -----END CERTIFICATE----- ``` 将整个输出(包括`BEGIN CERTIFICATE`和`END CERTIFICATE`行)复制到剪贴板。 在MySQL客户端上 ,在新目录中创建一个具有相同名称的文件: ```shell nano ~/client-ssl/ca.pem ``` 在内部,从剪贴板粘贴复制的证书内容。 保存并在完成后关闭文件。 接下来,在MySQL服务器上显示客户端证书: ```shell sudo cat /var/lib/mysql/client-cert.pem ``` ``` -----BEGIN CERTIFICATE----- . . . -----END CERTIFICATE----- ``` 再次,将内容复制到剪贴板。 记住包括第一行和最后一行。 在client-ssl目录下的MySQL客户端上打开一个具有相同名称的文件: ```shell nano ~/client-ssl/client-cert.pem ``` 粘贴剪贴板中的内容。 保存并关闭文件。 最后,在MySQL服务器上显示客户端密钥文件的内容: ```shell sudo cat /var/lib/mysql/client-key.pem ``` ``` Output -----BEGIN RSA PRIVATE KEY----- . . . -----END RSA PRIVATE KEY----- ``` 将显示的内容(包括第一行和最后一行)复制到剪贴板。 在MySQL客户端上 ,在client-ssl目录中打开一个具有相同名称的文件: ```shell nano ~/client-ssl/client-key.pem ``` 粘贴剪贴板中的内容。 保存并关闭文件。 客户端机器现在应具有访问MySQL服务器所需的所有凭据。 接下来,我们需要改变我们的远程用户。 ## 7.2需要远程用户的受信任的CA的证书(双向认证) 目前,MySQL客户端具有可用于在连接时向服务器提供其证书的文件。 但是,服务器仍未设置为要求来自受信任的CA的客户端证书。 要更改此,请在MySQL服务器上再次登录MySQL根帐户: ```shell mysql -u root -p ``` 接下来,我们需要更改对远程用户的要求。 而不是REQUIRE SSL子句,我们需要应用REQUIRE X509子句。 这意味着由先前需求提供的所有安全性,但另外需要连接客户端呈现由MySQL服务器信任的证书机构签署的证书。 要调整用户要求,请使用ALTER USER命令: ```sql ALTER USER 'remote_user'@'mysql_client_IP' REQUIRE X509; ``` 刷新更改以确保立即应用更改: ```sql FLUSH PRIVILEGES; ``` 完成后退出到shell: ```sql exit ``` 接下来,我们可以测试,以确保我们仍然可以连接。 连接时测试证书验证 现在是检查我们是否可以在连接时验证双方的好时机。 在MySQL客户端上 ,首先尝试连接而不提供客户端证书: ```shell mysql -u remote_user -p -h mysql_server_IP ``` ``` ERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_client_IP' (using password: YES) ``` 不提供客户端证书,服务器拒绝连接。 现在,使用--ssl-ca , --ssl-cert和--ssl-key选项指向~/client-ssl目录中的相关文件,进行连接: ```shell mysql -u remote_user -p -h mysql_server_IP --ssl-ca=~/client-ssl/ca.pem --ssl-cert=~/client-ssl/client-cert.pem --ssl-key=~ ``` 您应该成功登录。 注销以重新获得对shell会话的访问: ```sql exit ``` 现在我们已经确认访问服务器,我们可以实现一个小的可用性改进。 ## 7.3创建MySQL客户端配置文件 为了避免每次连接时都指定证书文件,我们可以创建一个简单的MySQL客户端配置文件。 在MySQL客户端机器上的主目录中,创建一个名为~/.my.cnf的隐藏文件: ```shell nano ~/.my.cnf ``` 在文件的顶部,创建一个名为[client]的部分。 在下面,我们可以设置ssl-ca , ssl-cert和ssl-key选项,以指向我们从服务器复制的文件。 它应该看起来像这样: ``` [client] ssl-ca = ~/client-ssl/ca.pem ssl-cert = ~/client-ssl/client-cert.pem ssl-key = ~/client-ssl/client-key.pem ``` ssl-ca选项告诉客户端验证MySQL服务器提供的证书是否由我们指向的证书颁发机构签名。 这允许客户端相信它正在连接到可信的MySQL服务器。 ssl-cert和ssl-key选项指向向MySQL服务器证明它也具有由相同证书颁发机构签名的证书所需的文件。 我们需要这个,如果我们想要MySQL服务器验证客户端也被CA信任。 保存并在完成后关闭文件。 现在,您可以连接到MySQL服务器,而不在命令行中添加--ssl-ca , --ssl-cert和--ssl-key选项: ```shell mysql -u remote_user -p -h mysql_server_ip ``` 您的客户端和服务器现在应该在协商连接时显示证书。 每个方都配置为根据本地CA证书验证远程证书。 # 8.结论 您的MySQL服务器现在应配置为要求远程客户端的安全连接。 此外,如果您按照步骤验证使用证书颁发机构的连接,双方建立一定程度的信任,远程方是合法的。 [非原创,改自《如何在Ubuntu 16.04上配置MySQL的SSL / TLS》