如何在Ubuntu 18.04上为MySQL配置SSL / TLS

如果您需要从远程位置访问MySQL数据库,那么安全地执行此操作非常重要。本指南将演示如何在Ubuntu 18.04上配置MySQL以接受使用SSL / TLS加密的远程连接。

介绍

MySQL是世界上最流行的开源关系数据库管理系统。 虽然现代包管理器已经减少了启动和运行MySQL的一些摩擦,但是在安装它之后还应该执行一些进一步的配置。 花费一些额外时间的最重要方面之一是安全性。

默认情况下,MySQL配置为仅接受本地连接,或者来自安装MySQL的同一台机器的连接。 如果您需要从远程位置访问MySQL数据库,那么安全地执行此操作非常重要。 在本指南中,我们将演示如何在Ubuntu 18.04上配置MySQL以接受使用SSL / TLS加密的远程连接。

先决条件

要完成本指南,您需要:

  • 两台 Ubuntu 18.04服务器。 我们将使用其中一个服务器作为MySQL服务器,而我们将另一个用作客户机。 创建具有sudo权限的非root用户, ufw在每个服务器上启用带有ufw的防火墙。 按照我们的Ubuntu 18.04初始服务器设置指南 ,让两台服务器进入适当的初始状态。
  • 其中一台机器上 ,安装并配置MySQL服务器。 按照我们的Ubuntu 18.04 MySQL安装指南中的 第1步到3执行此操作。 在遵循本指南时,请确保将 MySQL用户配置为使用密码进行身份验证,如本指南的第3步所述,因为这是使用TCP而不是本地Unix套接字连接到MySQL所必需的。

请注意,在本指南中,您安装MySQL的服务器将被称为MySQL服务器,并且应在此计算机上运行的任何命令都将以蓝色背景显示,如下所示:


同样,本指南将其他服务器称为MySQL客户端,并且必须在该计算机上运行的任何命令都将以红色背景显示:


在您按照本教程时请记住这些,以避免任何混淆。

第1步 - 检查MySQL的当前SSL / TLS状态

在进行任何配置更改之前,您可以检查MySQL服务器实例上的当前SSL / TLS状态。

使用以下命令以root用户身份开始MySQL会话。 此命令包含-p选项,该选项指示mysql提示您输入密码以进行登录。它还包括-h选项,该选项用于指定要连接的主机。 在这种情况下,它指向127.0.0.1 ,IPv4环回接口也称为localhost 这将强制客户端使用TCP连接而不是使用本地套接字文件。 MySQL默认尝试通过Unix套接字文件建立连接。 这通常更快,更安全,因为这些连接只能在本地进行,不必经过TCP连接必须执行的所有检查和路由操作。 但是,使用TCP连接可以检查连接的SSL状态:

mysql -u root -p -h 127.0.0.1

系统将提示您输入安装和配置MySQL时选择的MySQL root密码。 输入后,您将进入交互式MySQL会话。

显示发出以下命令的SSL / TLS变量的状态:

SHOW VARIABLES LIKE '%ssl%';
+---------------+----------+
| 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_opensslhave_ssl变量都标记为DISABLED 这意味着SSL功能已编译到服务器中,但尚未启用。

检查当前连接的状态以确认:

\s
--------------
mysql  Ver 14.14 Distrib 5.7.26, for Linux (x86_64) using  EditLine wrapper

Connection id:      9
Current database:   
Current user:       root@localhost
SSL:         Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.26-0ubuntu0.18.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:         40 min 11 sec

Threads: 1  Questions: 33  Slow queries: 0  Opens: 113  Flush tables: 1  Open tables: 106  Queries per second avg: 0.013
--------------

如上面的输出所示,即使您通过TCP连接,SSL也不会用于此连接。

完成后关闭当前的MySQL会话:

exit

现在您已确认您的MySQL服务器未使用SSL,您可以继续下一步,通过生成一些证书和密钥开始启用SSL的过程。 这些将允许您的服务器和客户端安全地相互通信。

第2步 - 生成SSL / TLS证书和密钥

要启用与MySQL的SSL连接,首先需要生成相应的证书和密钥文件。 MySQL 5.7及更高版本提供了一个名为mysql_ssl_rsa_setup的实用程序,可帮助简化此过程。 您通过遵循先决条件MySQL教程安装的MySQL版本包含此实用程序,因此我们将在此处使用它来生成必要的文件。

MySQL进程必须能够读取生成的文件,因此使用--uid选项将mysql声明为应拥有生成文件的系统用户:

sudo 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'
-----

这些新文件将存储在MySQL的数据目录中,默认位于/var/lib/mysql 键入以下命令检查生成的文件:

sudo find /var/lib/mysql -name '*.pem' -ls
   258930      4 -rw-r--r--   1 mysql    mysql        1107 May  3 16:43 /var/lib/mysql/client-cert.pem
   258919      4 -rw-r--r--   1 mysql    mysql         451 May  3 16:43 /var/lib/mysql/public_key.pem
   258925      4 -rw-------   1 mysql    mysql        1675 May  3 16:43 /var/lib/mysql/server-key.pem
   258927      4 -rw-r--r--   1 mysql    mysql        1107 May  3 16:43 /var/lib/mysql/server-cert.pem
   258922      4 -rw-------   1 mysql    mysql        1675 May  3 16:43 /var/lib/mysql/ca-key.pem
   258928      4 -rw-------   1 mysql    mysql        1675 May  3 16:43 /var/lib/mysql/client-key.pem
   258924      4 -rw-r--r--   1 mysql    mysql        1107 May  3 16:43 /var/lib/mysql/ca.pem
   258918      4 -rw-------   1 mysql    mysql        1679 May  3 16:43 /var/lib/mysql/private_key.pem

这些文件是证书颁发机构(以“ca”开头),MySQL服务器进程(以“server”开头)和MySQL客户端(以“client”开头)的密钥和证书对。 此外,MySQL使用private_key.pempublic_key.pem文件在不使用SSL时安全地传输密码。

现在您已拥有必要的证书和密钥文件,继续在MySQL实例上启用SSL。

第3步 - 在MySQL服务器上启用SSL连接

当服务器启动时,现代版本的MySQL会在MySQL数据目录中查找相应的证书文件。 因此,您无需修改​​MySQL的配置即可启用SSL。

而是通过重新启动MySQL服务来启用SSL:

sudo systemctl restart mysql

重新启动后,使用与以前相同的命令打开新的MySQL会话。 如果服务器支持,MySQL客户端将自动尝试使用SSL进行连接:

mysql -u root -p -h 127.0.0.1

让我们再看一下上次请求的相同信息。 检查SSL相关变量的值:

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)

have_opensslhave_ssl变量现在读为YES而不是DISABLED 此外, ssl_cassl_certssl_key变量已填充了我们刚生成的相应文件的名称。

接下来,再次检查连接详细信息:

\s
--------------
. . .
SSL:            Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection:      127.0.0.1 via TCP/IP
. . .
--------------

这次,将显示特定的SSL密码,表示正在使用SSL来保护连接。

退出到shell:

exit

您的服务器现在能够使用加密,但需要一些其他配置才能允许远程访问并强制使用安全连接。

第4步 - 为远程客户端配置安全连接

现在您已在MySQL服务器上启用SSL,您可以开始配置安全远程访问。 为此,您需要将MySQL服务器配置为要求通过SSL建立任何远程连接,绑定MySQL以监听公共接口,并调整系统的防火墙规则以允许外部连接

目前,MySQL服务器配置为接受来自客户端的SSL连接。 但是,如果客户端请求,它仍将允许未加密的连接。 我们可以通过启用require_secure_transport选项来更改此设置。 这要求所有连接都使用SSL或本地Unix套接字。 由于Unix套接字只能从服务器本身访问,因此远程用户可用的唯一连接选项将使用SSL。

要启用此设置,请在首选文本编辑器中打开MySQL配置文件。 在这里,我们将使用nano

sudo nano /etc/mysql/my.cnf

里面会有两个!includedir指令,用于获取其他配置文件。 您必须这些行添加自己的配置以便它覆盖这些附加配置文件中找到的任何冲突设置。

首先创建一个[mysqld]部分来定位MySQL服务器进程。 在该节标题下,将require_secure_transport设置为ON ,这将强制MySQL仅允许安全连接:

/etc/mysql/my.cnf
. . .

!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配置为仅监听源自127.0.0.1连接, 127.0.0.1是表示localhost的环回IP地址。 这意味着MySQL配置为仅监听源自安装MySQL服务器的计算机的连接。

为了允许MySQL监听外部连接,您必须将其配置为监听外部 IP地址上的连接。 为此,您可以添加bind-address设置并将其指向0.0.0.0 ,这是一个表示所有IP地址的通配符IP地址。 从本质上讲,这将迫使MySQL在每个接口上监听连接:

/etc/mysql/my.cnf
. . .

!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

注意:您也可以将bind-address设置为MySQL服务器的公共IP地址。 但是,如果您将数据库迁移到另一台计算机,则需要记住更新my.cnf文件。

添加这些行后,保存并关闭该文件。 如果您使用nano编辑文件,可以按CTRL+XY ,然后按ENTER

接下来,重新启动MySQL以应用新设置:

sudo systemctl restart mysql

通过键入以下内容,验证MySQL是否正在监听0.0.0.0而不是127.0.0.1

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      13317/mysqld        
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1293/sshd           
tcp6       0      0 :::22                   :::*                    LISTEN      1293/sshd           

上面输出中突出显示的0.0.0.0表示MySQL正在监听所有可用接口上的连接。

接下来,通过服务器的防火墙允许MySQL连接。 键入以下命令为您的ufw规则添加例外:

sudo ufw allow mysql
Rule added
Rule added (v6)

这样,远程连接尝试现在可以到达您的MySQL服务器。 但是,您当前没有配置任何可以从远程计算机连接的用户。 我们将创建并配置一个MySQL用户,该用户可以在下一步中从客户端计算机进行连接。

第5步 - 创建专用MySQL用户

此时,您的MySQL服务器将拒绝任何从远程客户端计算机连接的尝试。 这是因为现有的MySQL用户都只配置为从MySQL服务器本地连接。 要解决此问题,您将创建一个只能从客户端计算机连接的专用用户。

要创建此类用户,请以root用户身份重新登录MySQL:

mysql -u root -p

在提示符下,使用CREATE USER命令创建新的远程用户。 您可以根据需要为此用户命名,但在本指南中我们将其命名为mysql_user 请务必在用户规范的主机部分中指定客户端计算机的IP地址,以限制与该计算机的连接,并使用您选择的安全密码替换password 此外,对于将来关闭require_secure_transport选项的某些冗余,请通过包含REQUIRE SSL子句指定此用户需要SSL,如下所示:

CREATE USER 'mysql_user'@'your_mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL;

接下来,为他们应该有权访问的任何数据库或表授予新用户权限。 要演示,请创建一个example数据库:

CREATE DATABASE example;

然后让新用户访问此数据库及其所有表:

GRANT ALL ON example.* TO 'mysql_user'@'your_mysql_client_IP';

接下来,刷新权限以立即应用这些设置:

FLUSH PRIVILEGES;

完成后退出到shell:

exit

您的MySQL服务器现在已设置为允许来自远程用户的连接。 要测试您是否可以成功连接到MySQL,您需要在MySQL客户 mysql-client上安装mysql-client软件包。

使用ssh登录客户端计算机

ssh sammy@your_mysql_client_ip

然后更新客户端计算机的包索引:

sudo apt update

并使用以下命令安装mysql-client

sudo apt install mysql-client

出现提示时,按ENTER确认安装。

APT完成安装包后,运行以下命令以测试是否可以成功连接到服务器。 此命令包括指定mysql_user-u user选项和指定MySQL服务器 IP地址的-h选项:

mysql -u mysql_user -p -h your_mysql_server_IP

提交密码后,您将登录到远程服务器。 使用\s检查服务器的状态并确认您的连接是否安全:

\s
--------------
. . .
SSL:         Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection:      your_mysql_server_IP via TCP/IP
. . .
--------------

退出到shell:

exit

您已经确认您可以通过SSL连接到MySQL。 但是,您尚未确认MySQL服务器拒绝不安全的连接。 要测试这一点,请尝试再次连接,但这次将--ssl-mode=disabled附加到login命令。 这将指示mysql-client尝试未加密的连接:

mysql -u mysql_user -p -h mysql_server_IP --ssl-mode=disabled

在出现提示时输入密码后,您的连接将被拒绝:

ERROR 1045 (28000): Access denied for user 'mysql_user'@'mysql_server_IP' (using password: YES)

这表明在未加密的连接被拒绝时允许SSL连接。

此时,您的MySQL服务器已配置为接受安全的远程连接。 如果这满足您的安全要求,您可以在此处停止,但是您可以使用一些其他部分来增强两台服务器之间的安全性和信任。

第6步 - (可选)配置MySQL连接的验证

目前,您的MySQL服务器配置了由本地生成的证书颁发机构(CA)签名的SSL证书。 服务器的证书和密钥对足以为传入连接提供加密。

但是,您尚未完全利用证书颁发机构可以提供的信任关系。 通过将CA证书分发给客户端 - 以及客户端证书和密钥 - 双方都可以提供其证书由相互信任的证书颁发机构签名的证据。 这有助于防止来自恶意服务器的欺骗性连接。

为了实现这个额外的可选安全措施,我们将相应的SSL文件传输到客户端计算机,创建客户端配置文件,并更改远程MySQL用户以要求可信证书。

注意:将CA证书,客户端证书和客户端密钥传输到以下段落中概述的MySQL客户端的过程涉及使用cat显示每个文件的内容,将这些内容复制到剪贴板,并将它们粘贴到新文件中。客户机器。 虽然可以使用scpsftp等程序直接复制这些文件,但这也要求您为两台服务器设置SSH密钥 ,以便允许它们通过SSH进行通信。

我们的目标是将连接MySQL服务器的潜在渠道数量降至最低。 虽然此过程比直接传输文件稍微费力,但它同样安全,并且不需要您在两台计算机之间打开SSH连接。

首先在非root用户的主目录中的MySQL客户端上创建一个目录。 将此目录client-ssl

mkdir ~/client-ssl

由于证书密钥是敏感的,因此锁定对此目录的访问权限,以便只有当前用户才能访问它:

chmod 700 ~/client-ssl

MySQL服务器上 ,键入以下内容显示CA证书的内容:

sudo cat /var/lib/mysql/ca.pem
-----BEGIN CERTIFICATE-----

. . .

-----END CERTIFICATE-----

将整个输出(包括BEGIN CERTIFICATEEND CERTIFICATE行)复制到剪贴板。

MySQL客户端上 ,在新目录中创建一个具有相同名称的文件:

nano ~/client-ssl/ca.pem

在里面,从剪贴板粘贴复制的证书内容。 完成后保存并关闭文件。

接下来,在MySQL服务器上显示客户端证书:

sudo cat /var/lib/mysql/client-cert.pem
-----BEGIN CERTIFICATE-----

. . .

-----END CERTIFICATE-----

将文件内容复制到剪贴板。 再次,请记住包括第一行和最后一行。

client-ssl目录下的MySQL客户端上打开一个具有相同名称的文件:

nano ~/client-ssl/client-cert.pem

粘贴剪贴板中的内容。 保存并关闭文件。

最后,在MySQL服务器上显示客户端密钥文件的内容:

sudo cat /var/lib/mysql/client-key.pem
-----BEGIN RSA PRIVATE KEY-----

. . .

-----END RSA PRIVATE KEY-----

将显示的内容(包括第一行和最后一行)复制到剪贴板。

MySQL客户端上 ,在client-ssl目录中打开一个具有相同名称的文件:

nano ~/client-ssl/client-key.pem

粘贴剪贴板中的内容。 保存并关闭文件。

客户端计算机现在具有访问MySQL服务器所需的所有凭据。 但是,MySQL服务器仍未设置为要求客户端连接的可信证书。

要更改此设置,请在MySQL服务器上再次登录MySQL root帐户:

mysql -u root -p

从此处,更改远程用户的安全要求。 而不是REQUIRE SSL子句,应用REQUIRE X509子句。 这意味着REQUIRE SSL子句提供的所有安全性,但还要求连接客户端提供由MySQL服务器信任的证书颁发机构签名的证书。

要调整用户要求,请使用ALTER USER命令:

ALTER USER 'mysql_user'@'mysql_client_IP' REQUIRE X509;

然后刷新更改以确保立即应用它们:

FLUSH PRIVILEGES;

完成后退出到shell:

exit

然后,检查您是否可以在连接时验证双方。

MySQL客户端上 ,首先尝试连接而不提供客户端证书:

mysql -u mysql_user -p -h mysql_server_IP
ERROR 1045 (28000): Access denied for user 'mysql_user'@'mysql_client_IP' (using password: YES)

正如所料,服务器在没有提供客户端证书时拒绝连接。

现在,使用--ssl-ca~/client-ssl --ssl-cert--ssl-key选项连接以指向~/client-ssl目录中的相关文件:

mysql -u mysql_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客户端计算机上的主目录中,创建一个名为~/.my.cnf的隐藏配置文件:

nano ~/.my.cnf

在文件的顶部,创建一个名为[client]的部分。 在下面,添加ssl-cassl-certssl-key选项,并将它们指向您从服务器复制的相应文件。 它看起来像这样:

〜/ .my.cnf
[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-certssl-key选项指向向MySQL服务器证明它也具有由相同证书颁发机构签名的证书所需的文件。 如果您希望MySQL服务器验证客户端是否也受CA信任,那么您将需要这个。

完成后保存并关闭文件。

现在,您可以连接到MySQL服务器,而无需在命令行上添加--ssl-ca , - --ssl-cert--ssl-key选项:

mysql -u remote_user -p -h mysql_server_ip

您的客户端和服务器现在将在协商连接时各自提供证书。 每一方都配置为根据其本地CA证书验证远程证书。

结论

您的MySQL服务器现在配置为需要来自远程客户端的安全连接。 此外,如果您按照步骤使用证书颁发机构验证连接,则双方都会建立一定程度的信任,即远程方是合法的。