介绍
MySQL是世界上最流行的开源关系数据库管理系统。 现代包管理器已经减少了使MySQL运行的一些困难,但仍然有一些配置,应该在安装后完成。 花费一些额外时间的最重要的领域之一是安全。
默认情况下,MySQL配置为只接受本地连接。 如果需要允许远程连接,请务必这样做。 在本指南中,我们将演示如何在Ubuntu 16.04上配置MySQL以接受使用SSL / TLS加密的远程连接。
先决条件
要遵循本指南,您将需要两个 Ubuntu 16.04服务器。 我们将使用一个作为MySQL服务器,另一个作为客户端。 在每个服务器上创建具有sudo
权限的非root用户。 按照我们的Ubuntu 16.04初始服务器设置指南 ,让您的服务器进入适当的初始状态。
在第一台机器上,您应该安装并配置MySQL服务器 。 按照我们的Ubuntu 16.04的MySQL安装指南安装和配置软件。
在第二台机器上,安装MySQL客户端软件包。 您可以通过键入以下内容更新apt
软件包索引并安装必要的软件:
sudo apt-get update
sudo apt-get install mysql-client
当您的服务器和客户端准备就绪后,请继续下面。
检查当前SSL / TLS状态
在我们开始之前,我们可以检查我们的MySQL服务器实例上的SSL / TLS的当前状态。
使用root
MySQL用户登录MySQL会话。 我们将使用-h
指定IPv4本地环回接口,以强制客户端与TCP连接,而不是使用本地套接字文件。 这将允许我们检查TCP连接的SSL状态:
mysql -u root -p -h 127.0.0.1
系统将提示您输入在安装过程中选择的MySQL root
密码。 之后,您将被放入交互式MySQL会话。
键入以下内容以显示SSL / TLS变量的状态:
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
变量都标记为DISABLED
。 这意味着SSL功能已编译到服务器中,但尚未启用。
检查我们当前连接的状态以确认:
\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目前不用于我们的连接,即使我们通过TCP连接。
完成后关闭当前MySQL会话:
exit
现在我们可以开始配置MySQL的SSL来保护我们的连接。
生成SSL / TLS证书和密钥
要启用到MySQL的SSL连接,我们首先需要生成相应的证书和密钥文件。 MySQL 5.7及更高版本提供了一个名为mysql_ssl_rsa_setup
的实用程序,以简化此过程。 Ubuntu 16.04有一个兼容版本的MySQL,所以我们可以使用这个命令来生成必要的文件。
这些文件将在MySQL的数据目录中创建,位于/var/lib/mysql
。 我们需要MySQL进程能够读取生成的文件,所以我们将传递mysql
作为应该拥有生成的文件的用户:
sudo mysql_ssl_rsa_setup --uid=mysql
生成将产生看起来像这样的输出:
OutputGenerating 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'
-----
键入以下内容检查生成的文件:
sudo find /var/lib/mysql -name '*.pem' -ls
Output 256740 4 -rw-r--r-- 1 mysql mysql 1078 Mar 17 17:24 /var/lib/mysql/server-cert.pem
256735 4 -rw------- 1 mysql mysql 1675 Mar 17 17:24 /var/lib/mysqlsql/ca-key.pem<^>
256739 4 -rw-r--r-- 1 mysql mysql 451 Mar 17 17:24 /var/lib/mysqlsql/public_key.pem<^>
256741 4 -rw------- 1 mysql mysql 1679 Mar 17 17:24 /var/lib/mysqlsql/client-key.pem<^>
256737 4 -rw-r--r-- 1 mysql mysql 1074 Mar 17 17:24 /var/lib/mysqlsql/ca.pem<^>
256743 4 -rw-r--r-- 1 mysql mysql 1078 Mar 17 17:24 /var/lib/mysqlsql/client-cert.pem<^>
256736 4 -rw------- 1 mysql mysql 1675 Mar 17 17:24 /var/lib/mysqlsql/private_key.pem<^>
256738 4 -rw------- 1 mysql mysql 1675 Mar 17 17:24 /var/lib/mysqlsql/server-key.pem<^>
最后一列显示生成的文件名。 显示“mysql”的中心列表示生成的文件具有正确的用户和组所有权。
这些文件是证书颁发机构(以“ca”开头),MySQL服务器进程(以“服务器”开头)和MySQL客户端(以“客户端”开头)的密钥和证书对。 此外,当不使用SSL时,MySQL使用private_key.pem
和public_key.pem
文件来安全地传输密码。
在MySQL服务器上启用SSL连接
现代MySQL版本将在服务器启动时在MySQL数据目录中查找相应的证书文件。 因此,我们实际上不需要修改MySQL配置来启用SSL。
我们可以重新启动MySQL服务:
sudo systemctl restart mysql
重新启动后,使用与以前相同的命令打开一个新的MySQL会话。 如果服务器支持,MySQL客户端将自动尝试使用SSL进行连接:
mysql -u root -p -h 127.0.0.1
让我们来看看我们上次请求的相同信息。 检查SSL相关变量的值:
SHOW VARIABLES LIKE '%ssl%';
Output+---------------+-----------------+
| 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)
这次, have_openssl
和have_ssl
变量读取“YES”而不是“DISABLED”。 此外, ssl_ca
, ssl_cert
和ssl_key
变量已用我们生成的相关证书的名称填充。
接下来,再次检查连接详细信息:
\s
Output--------------
. . .
SSL: Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection: 127.0.0.1 via TCP/IP
. . .
--------------
这一次,将显示特定的SSL密码,指示正在使用SSL来保护我们的连接。
退出到shell:
exit
我们的服务器现在能够使用加密,但是需要一些额外的配置来允许远程访问和强制使用安全连接。
为远程客户端配置安全连接
现在我们已在服务器上提供SSL,我们可以开始配置安全远程访问。 为此,我们需要:
- 需要SSL用于远程连接
- 绑定到公共接口
- 为远程连接创建MySQL用户
- 调整我们的防火墙规则以允许外部连接
使用强制SSL配置远程访问
目前,MySQL服务器配置为接受来自客户端的SSL连接。 但是,如果客户端请求,它仍然允许未加密的连接。
我们可以通过打开require_secure_transport
选项来解决这个问题。 这需要所有连接都使用SSL或本地Unix套接字。 由于只能从服务器本身访问Unix套接字,因此对远程用户开放的唯一连接选项将使用SSL。
要启用此设置,请在文本编辑器中打开/etc/mysql/my.cnf
文件:
sudo nano /etc/mysql/my.cnf
在里面,会有两个!includedir
指令用于源额外的配置文件。 我们需要在这些行下面放置我们自己的配置,以便覆盖任何冲突的设置。
首先创建一个[mysqld]
节来定位MySQL服务器进程。 在该节标题下,将require_secure_transport
设置为ON
:
. . .
!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”:
. . .
!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以应用新设置:
sudo systemctl restart mysql
验证MySQL是否正在监听“0.0.0.0”而不是“127.0.0.1”通过键入:
sudo netstat -plunt
OutputActive 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
上面输出中的“0.0.0.0”表示MySQL正在监听所有可用接口上的连接。
接下来,我们需要通过我们的防火墙允许MySQL连接。 通过键入以下命令创建异常:
sudo ufw allow mysql
OutputRule added
Rule added (v6)
远程连接尝试现在应该能够到达我们的MySQL服务器。
配置远程MySQL用户
MySQL服务器现在正在监听远程连接,但是我们当前没有配置任何用户可以从外部计算机连接的用户。
以root
用户身份登录MySQL以开始:
mysql -u root -p
在里面,您可以使用CREATE USER
命令创建一个新的远程用户。 我们将在用户规范的主机部分使用我们的客户端机器的IP地址来限制与该机器的连接。
对于将来require_secure_transport
选项关闭时的一些冗余,我们还将在创建帐户期间指定此用户通过包含REQUIRE SSL
子句来REQUIRE SSL
:
CREATE USER 'remote_user'@'mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL;
接下来,授予他们应该有权访问的数据库或表的新用户权限。 为了演示,我们将创建一个example
数据库,并赋予我们新的用户所有权:
CREATE DATABASE example;
GRANT ALL ON example.* TO 'remote_user'@'mysql_client_IP';
接下来,刷新权限以立即应用这些设置:
FLUSH PRIVILEGES;
完成后退出到shell:
exit
我们的服务器设置为允许连接到我们的远程用户。
测试远程连接
在MySQL客户端计算机上,测试以确保可以成功连接到服务器。 使用-u
选项指定远程用户,使用-h
选项指定MySQL服务器的IP地址:
mysql -u remote_user -p -h mysql_server_IP
指定密码后,您将登录到远程服务器。
检查以确保您的连接安全:
\s
Output--------------
. . .
SSL: Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection: mysql_server_IP via TCP/IP
. . .
--------------
退出到shell:
exit
接下来,尝试连接不安全:
mysql -u remote_user -p -h mysql_server_IP --ssl-mode=disabled
提示您输入密码后,应拒绝您的连接:
OutputERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_server_IP' (using password: YES)
这是我们正在努力。 它显示允许SSL连接,而未加密的连接被拒绝。
此时,我们的MySQL服务器已配置为安全地接受远程连接。 如果这满足您的安全要求,您可以停止这里,但我们可以添加一些额外的部分,以进一步提高我们的安全性和信任。
配置MySQL连接验证(可选)
目前,我们的MySQL服务器配置有由本地生成的证书颁发机构(CA)签名的SSL证书。 服务器的证书和密钥对足以为传入连接提供加密。
但是,我们目前没有利用证书颁发机构可以提供的信任关系。 通过将CA证书分发给客户端以及客户端证书和密钥,双方可以提供其证书由相互信任的证书颁发机构签名的证明。 这可以帮助防止恶意服务器的欺骗性连接。
为了实施这个额外的可选保护措施,我们需要:
- 将适当的SSL文件传输到客户端计算机
- 创建客户端配置文件
- 更改远程用户以要求受信任的证书
将客户端证书传输到客户端计算机
首先,我们需要从MySQL服务器获取MySQL CA和客户端证书文件,并将它们放在MySQL客户端上。
首先在MySQL客户端上的用户的主目录中创建一个目录,用于连接。 调用此client-ssl
:
mkdir ~/client-ssl
由于证书密钥是敏感的,我们应该锁定对此目录的访问,以便只有当前用户可以访问它:
chmod 700 ~/client-ssl
现在,我们可以将证书信息复制到新目录。
在MySQL服务器计算机上,通过键入以下内容显示CA证书的内容:
sudo cat /var/lib/mysql/ca.pem
Output-----BEGIN CERTIFICATE-----
. . .
-----END CERTIFICATE-----
将整个输出(包括BEGIN CERTIFICATE
和END CERTIFICATE
行)复制到剪贴板。
在MySQL客户端上 ,在新目录中创建一个具有相同名称的文件:
nano ~/client-ssl/ca.pem
在内部,从剪贴板粘贴复制的证书内容。 保存并在完成后关闭文件。
接下来,在MySQL服务器上显示客户端证书:
sudo cat /var/lib/mysql/client-cert.pem
Output-----BEGIN CERTIFICATE-----
. . .
-----END CERTIFICATE-----
再次,将内容复制到剪贴板。 记住包括第一行和最后一行。
在client-ssl
目录下的MySQL客户端上打开一个具有相同名称的文件:
nano ~/client-ssl/client-cert.pem
粘贴剪贴板中的内容。 保存并关闭文件。
最后,在MySQL服务器上显示客户端密钥文件的内容:
sudo cat /var/lib/mysql/client-key.pem
Output-----BEGIN RSA PRIVATE KEY-----
. . .
-----END RSA PRIVATE KEY-----
将显示的内容(包括第一行和最后一行)复制到剪贴板。
在MySQL客户端上 ,在client-ssl
目录中打开一个具有相同名称的文件:
nano ~/client-ssl/client-key.pem
粘贴剪贴板中的内容。 保存并关闭文件。
客户端机器现在应具有访问MySQL服务器所需的所有凭据。 接下来,我们需要改变我们的远程用户。
需要远程用户的受信任的CA的证书
目前,MySQL客户端具有可用于在连接时向服务器提供其证书的文件。 但是,服务器仍未设置为要求来自受信任的CA的客户端证书。
要更改此,请在MySQL服务器上再次登录MySQL根帐户:
mysql -u root -p
接下来,我们需要更改对远程用户的要求。 而不是REQUIRE SSL
子句,我们需要应用REQUIRE X509
子句。 这意味着由先前需求提供的所有安全性,但另外需要连接客户端呈现由MySQL服务器信任的证书机构签署的证书。
要调整用户要求,请使用ALTER USER
命令:
ALTER USER 'remote_user'@'mysql_client_IP' REQUIRE X509;
刷新更改以确保立即应用更改:
FLUSH PRIVILEGES;
完成后退出到shell:
exit
接下来,我们可以测试,以确保我们仍然可以连接。
连接时测试证书验证
现在是检查我们是否可以在连接时验证双方的好时机。
在MySQL客户端上 ,首先尝试连接而不提供客户端证书:
mysql -u remote_user -p -h mysql_server_IP
OutputERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_client_IP' (using password: YES)
不提供客户端证书,服务器拒绝连接。
现在,使用--ssl-ca
, --ssl-cert
和--ssl-key
选项指向~/client-ssl
目录中的相关文件,进行连接:
mysql -u remote_user -p -h mysql_server_IP --ssl-ca=~/client-ssl/ca.pem --ssl-cert=~/client-ssl/client-cert.pem --ssl-key=~/client-ssl/client-key.pem
您应该成功登录。 注销以重新获得对shell会话的访问:
exit
现在我们已经确认访问服务器,我们可以实现一个小的可用性改进。
创建MySQL客户端配置文件
为了避免每次连接时都指定证书文件,我们可以创建一个简单的MySQL客户端配置文件。
在MySQL客户端机器上的主目录中,创建一个名为~/.my.cnf
的隐藏文件:
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
选项:
mysql -u remote_user -p -h mysql_server_ip
您的客户端和服务器现在应该在协商连接时显示证书。 每个方都配置为根据本地CA证书验证远程证书。
结论
您的MySQL服务器现在应配置为要求远程客户端的安全连接。 此外,如果您按照步骤验证使用证书颁发机构的连接,双方建立一定程度的信任,远程方是合法的。