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

介绍

MySQL 是世界上最受欢迎的(https://db-engines.com/en/ranking)开源关系数据库管理系统. 虽然现代的包管理器已经减少了一些摩擦,以获得 MySQL 并运行,仍然有一些进一步的配置,你安装后应该执行。

默认情况下,MySQL 配置为仅接受本地连接,或来自安装 MySQL 的相同机器的连接. 如果您需要从远程位置访问您的 MySQL 数据库,重要的是您要安全地这样做. 在本指南中,我们将展示如何在 Ubuntu 18.04 上配置 MySQL 以接受 SSL/TLS 加密的远程连接。

前提条件

要完成本指南,您将需要:

*2个 Ubuntu 18.04 服务器。 我们将使用其中一个服务器作为MySQL服务器,而另一个服务器作为客户端机器. 创建一个具有 " sudo " 权限的非源用户,并在每个服务器上设置一个带有 " ufw " 的防火墙。 遵循我们的Ubuntu 18.04 初始服务器设置指南,使两个服务器进入适当的初始状态.

  • 联合国 在 ** 1 个机 上,安装并配置 MySQL 服务器. 遵循** 我们Ubuntu 18.04的Steps 1至3** 安装指南。 遵循此向导时, 请确定配置您的** root ** MySQL用户用密码认证,如指南的[步骤3(https://andsky.com/tech/tutorials/how-to-install-mysql-on-ubuntu-18-04# step-3-%E2%80%94-(optional)-调整-用户-认证-和-priviles所描述,因为这是使用TCP而不是本地Unix套接字连接MySQL所必需. .

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

1[environment second]

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

1[environment third]

请记住这些,当你跟随这个教程,以避免任何混淆。

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

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

使用以下命令开始 MySQL 会话作为 root MySQL 用户 。 此命令包括-p ' 选项,它指示mysql ' 提示您输入密码。 它还包括用于指定连接主机的 "-h " 选项。 在这种情况下,它将其指向`127.0.0.1',即IPv4回路接口,也称为** localhost** . 这将迫使客户端与 [TCP] (https://en.wikipedia.org/wiki/Transmission_Control_Protocol] 连接, 而不是使用本地套接字文件 。 MySQL 试图默认通过 [Unix socket 文件] (https://en.wikipedia.org/wiki/Unix_domain_socket ) 进行连接 。 这一般是比较快和比较安全的,因为这些连接只能在当地制造,不需要通过TCP连接必须进行的所有检查和通路操作. 然而,通过连接到TCP,我们可以检查连接的SSL状态:

1[environment second]
2mysql -u root -p -h 127.0.0.1

您将被提示使用您在安装和配置MySQL时所选择的MySQL root 密码。

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

1[environment second]
2SHOW VARIABLES LIKE '%ssl%';
 1[secondary_label Output]
 2[environment second]
 3+---------------+----------+
 4| Variable_name | Value    |
 5+---------------+----------+
 6| have_openssl  | DISABLED |
 7| have_ssl      | DISABLED |
 8| ssl_ca        |          |
 9| ssl_capath    |          |
10| ssl_cert      |          |
11| ssl_cipher    |          |
12| ssl_crl       |          |
13| ssl_crlpath   |          |
14| ssl_key       |          |
15+---------------+----------+
169 rows in set (0.01 sec)

have_opensslhave_ssl变量都标记为DISABLED,这意味着SSL功能已被编译到服务器中,但尚未启用。

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

1[environment second]
2\s
 1[secondary_label Output]
 2[environment second]
 3--------------
 4mysql Ver 14.14 Distrib 5.7.26, for Linux (x86_64) using EditLine wrapper
 5
 6Connection id:		9
 7Current database:	
 8Current user:		root@localhost
 9SSL:			Not in use
10Current pager:		stdout
11Using outfile:		''
12Using delimiter:	;
13Server version:		5.7.26-0ubuntu0.18.04.1 (Ubuntu)
14Protocol version:	10
15Connection:		127.0.0.1 via TCP/IP
16Server characterset:	latin1
17Db characterset:	latin1
18Client characterset:	utf8
19Conn. characterset:	utf8
20TCP port:		3306
21Uptime:			40 min 11 sec
22
23Threads: 1 Questions: 33 Slow queries: 0 Opens: 113 Flush tables: 1 Open tables: 106 Queries per second avg: 0.013
24--------------

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

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

1[environment second]
2exit

现在你已经确认你的MySQL服务器不使用SSL,你可以转到下一步,在那里你将通过生成一些证书和密钥开始启用SSL的过程。

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

要启用 SSL 连接到 MySQL,您首先需要生成相应的证书和密钥文件。 MySQL 版本 5.7 及以上提供一个名为 mysql_ssl_rsa_setup 的实用程序,这有助于简化此过程。 您通过遵循 [前提 MySQL 教程] 安装的 MySQL 版本(https://andsky.com/tech/tutorials/how-to-install-mysql-on-ubuntu-18-04)包含了此实用程序,所以我们将在这里使用它来生成必要的文件。

MySQL 流程必须能够读取生成的文件,所以使用 --uid' 选项来声明 mysql' 是应该拥有生成的文件的系统用户:

1[environment second]
2sudo mysql_ssl_rsa_setup --uid=mysql

这将产生类似于以下的输出:

 1[secondary_label Output]
 2[environment second]
 3Generating a 2048 bit RSA private key
 4.+++
 5..........+++
 6writing new private key to 'ca-key.pem'
 7-----
 8Generating a 2048 bit RSA private key
 9........................................+++
10............+++
11writing new private key to 'server-key.pem'
12-----
13Generating a 2048 bit RSA private key
14.................................+++
15............................................................+++
16writing new private key to 'client-key.pem'
17-----

这些新文件将存储在MySQL的数据目录中,默认位置为 /var/lib/mysql

1[environment second]
2sudo find /var/lib/mysql -name '*.pem' -ls
 1[secondary_label Output]
 2[environment second]
 3   258930 4 -rw-r--r--   1 mysql mysql 1107 May 3 16:43 /var/lib/mysql/client-cert.pem
 4   258919 4 -rw-r--r--   1 mysql mysql 451 May 3 16:43 /var/lib/mysql/public_key.pem
 5   258925 4 -rw-------   1 mysql mysql 1675 May 3 16:43 /var/lib/mysql/server-key.pem
 6   258927 4 -rw-r--r--   1 mysql mysql 1107 May 3 16:43 /var/lib/mysql/server-cert.pem
 7   258922 4 -rw-------   1 mysql mysql 1675 May 3 16:43 /var/lib/mysql/ca-key.pem
 8   258928 4 -rw-------   1 mysql mysql 1675 May 3 16:43 /var/lib/mysql/client-key.pem
 9   258924 4 -rw-r--r--   1 mysql mysql 1107 May 3 16:43 /var/lib/mysql/ca.pem
10   258918 4 -rw-------   1 mysql mysql 1679 May 3 16:43 /var/lib/mysql/private_key.pem

这些文件是证书权限的密钥和证书对(从),MySQL服务器流程(从),以及MySQL客户端(从)。

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

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

现代版本的MySQL在MySQL数据目录中寻找相应的证书文件,每次服务器启动,因此,您不需要修改MySQL的配置以启用SSL。

相反,通过重新启动MySQL服务来启用SSL:

1[environment second]
2sudo systemctl restart mysql

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

1[environment second]
2mysql -u root -p -h 127.0.0.1

让我们再来看看上次我们要求的相同信息,检查SSL相关变量的值:

1[environment second]
2SHOW VARIABLES LIKE '%ssl%';
 1[secondary_label Output]
 2[environment second]
 3+---------------+-----------------+
 4| Variable_name | Value           |
 5+---------------+-----------------+
 6| have_openssl  | YES             |
 7| have_ssl      | YES             |
 8| ssl_ca        | ca.pem          |
 9| ssl_capath    |                 |
10| ssl_cert      | server-cert.pem |
11| ssl_cipher    |                 |
12| ssl_crl       |                 |
13| ssl_crlpath   |                 |
14| ssl_key       | server-key.pem  |
15+---------------+-----------------+
169 rows in set (0.00 sec)

have_opensslhave_ssl变量现在读取YES而不是DISABLED。此外,ssl_ca,ssl_certssl_key变量已被填充到我们刚刚生成的相应文件的名称。

接下来,再检查连接细节:

1[environment second]
2\s
1[secondary_label Output]
2[environment second]
3--------------
4. . .
5SSL:			Cipher in use is DHE-RSA-AES256-SHA
6. . .
7Connection:		127.0.0.1 via TCP/IP
8. . .
9--------------

这次,显示了特定SSL加密器,表示SSL正在被用来保护连接。

退出回到壳:

1[environment second]
2exit

您的服务器现在可以使用加密,但需要一些额外的配置来允许远程访问并授权使用安全连接。

步骤4:为远程客户端配置安全连接

现在,您已在MySQL服务器上启用SSL,您可以开始配置安全的远程访问。 要做到这一点,您将配置您的MySQL服务器以要求任何远程连接通过SSL,将MySQL绑定到公共界面上聆听,并调整系统的防火墙规则以允许外部连接

目前,MySQL服务器已配置为接受客户端的SSL连接,但如果客户端要求,它仍然允许未加密的连接,我们可以通过打开require_secure_transport选项来改变这一点,这需要所有连接使用SSL或本地Unix插槽。

要启用此设置,请在您喜爱的文本编辑器中打开MySQL配置文件. 在这里,我们将使用nano:

1[environment second]
2sudo nano /etc/mysql/my.cnf

内部将有两个 !includedir 指令,用于来源额外的配置文件. 您必须在这些行中添加自己的配置 beneath ,以便它忽略在这些额外的配置文件中发现的任何矛盾的设置。

在该部分标题下,将require_secure_transport设置为ON,这将迫使MySQL只允许安全连接:

 1[label /etc/mysql/my.cnf]
 2[environment second]
 3. . .
 4
 5!includedir /etc/mysql/conf.d/
 6!includedir /etc/mysql/mysql.conf.d/
 7
 8[mysqld]
 9# Require clients to connect either using SSL
10# or through a local socket file
11require_secure_transport = ON

默认情况下,MySQL 配置为仅听取源于127.0.0.1的连接,即代表 localhost 的 loopback IP 地址,这意味着MySQL 配置为仅听取源于安装 MySQL 服务器的机器的连接。

为了允许 MySQL 聆听外部连接,您必须将其配置为在 external IP 地址上聆听连接。 要做到这一点,您可以添加bind-address设置,并将其指向0.0.0.0,这是代表所有 IP 地址的 wildcard IP 地址。

 1[label /etc/mysql/my.cnf]
 2[environment second]
 3. . .
 4
 5!includedir /etc/mysql/conf.d/
 6!includedir /etc/mysql/mysql.conf.d/
 7
 8[mysqld]
 9# Require clients to connect either using SSL
10# or through a local socket file
11require_secure_transport = ON
12bind-address = 0.0.0.0

<$>[注] 注: 您可以替代地将bind-address设置为您的MySQL服务器的公共IP地址,但是,如果您将数据库迁移到另一个机器,您需要记住更新您的my.cnf文件。

添加这些行后,保存并关闭文件. 如果您使用nano来编辑文件,您可以通过按CTRL+X,Y,然后ENTER来完成编辑。

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

1[environment second]
2sudo systemctl restart mysql

检查MySQL是否正在听0.0.0.0而不是127.0.0.1,键入:

1[environment second]
2sudo netstat -plunt

这个命令的输出将是这样的:

1[secondary_label Output]
2[environment second]
3Active Internet connections (only servers)
4Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name    
5tcp 0 0 0.0.0.0:3306 0.0.0.0:*               LISTEN 13317/mysqld        
6tcp 0 0 0.0.0.0:22 0.0.0.0:*               LISTEN 1293/sshd           
7tcp6 0 0 :::22                   :::*                    LISTEN 1293/sshd

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

接下来,允许MySQL连接通过服务器的防火墙。

1[environment second]
2sudo ufw allow mysql
1[secondary_label Output]
2[environment second]
3Rule added
4Rule added (v6)

通过此,远程连接尝试现在可以到达您的MySQL服务器,但是,您目前没有任何用户配置,可以从远程机器连接。

第5步:创建专用MySQL用户

在此时,您的MySQL服务器将拒绝任何从远程客户端机器连接的尝试. 这是因为现有的MySQL用户都仅配置为从MySQL服务器本地连接。

要创建此类用户,请重新登录 MySQL 作为 root 用户:

1[environment second]
2mysql -u root -p

从提示起,创建一个带有 " CREATE USER " 命令的新远程用户。 你可以给这个用户起任何名字,但在这个指南中,我们把它命名为mysql_user . 请在用户规格的主机部分指定客户机的IP地址,以限制与该机的连接,并用您选择的安全密码来替换密码。 此外,对于今后关闭 " 需要_安全-运输 " 选项时的某些冗余,请具体说明该用户需要SSL,包括`REQUIRE SSL'条款,如下文所示:

1[environment second]
2CREATE USER 'mysql_user'@'your_mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL;

接下来,在他们应该访问的数据库或表上授予新用户权限,以示范,创建一个示例数据库:

1[environment second]
2CREATE DATABASE example;

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

1[environment second]
2GRANT ALL ON example.* TO 'mysql_user'@'your_mysql_client_IP';

接下来,清除权限,立即应用这些设置:

1[environment second]
2FLUSH PRIVILEGES;

然后离开后回到壳,当你完成:

1[environment second]
2exit

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

登录您的客户端机器使用ssh

1[environment local]
2ssh sammy@your_mysql_client_ip

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

1[environment third]
2sudo apt update

然后用以下命令安装mysql-client:

1[environment third]
2sudo apt install mysql-client

当被提示时,通过按ENTER来确认安装。

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

1[environment third]
2mysql -u mysql_user -p -h your_mysql_server_IP

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

1[environment third]
2\s
1[secondary_label Output]
2[environment third]
3--------------
4. . .
5SSL:			Cipher in use is DHE-RSA-AES256-SHA
6. . .
7Connection:		your_mysql_server_IP via TCP/IP
8. . .
9--------------

退出回到壳:

1[environment third]
2exit

您已确认可以通过 SSL 连接到 MySQL. 但是,您尚未确认 MySQL 服务器正在拒绝不安全的连接. 要测试此情况,请尝试连接一次,但这一次将--ssl-mode=disabled附加到登录命令中。

1[environment third]
2mysql -u mysql_user -p -h mysql_server_IP --ssl-mode=disabled

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

1[secondary_label Output]
2[environment third]
3ERROR 1045 (28000): Access denied for user 'mysql_user'@'mysql_server_IP' (using password: YES)

这表明SSL连接允许,而未加密连接被拒绝。

在此时,您的MySQL服务器已配置为接受安全的远程连接,如果满足您的安全要求,您可以停留在这里,但您可以设置一些额外的部件来增强您的两个服务器之间的安全性和信任。

步骤 6 — (可选) 配置 MySQL 连接的验证

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

但是,您还没有充分利用证书授权机构可以提供的信任关系。通过向客户分发 CA 证书 — 以及客户端证书和密钥 — 双方都可以提供证据,证明他们的证书是由相互信任的证书授权机构签署的。

为了实现这个额外的、可选的保护,我们将将相应的SSL文件传输到客户端机器,创建客户端配置文件,并更改远程MySQL用户以要求一个值得信赖的证书。

<美元 > [注] 注: 以下段落中概述的向 MySQL 客户端传输CA证书,客户端证书和客户端密钥的过程涉及用"cat"显示每个文件的内容,将这些内容复制到您的剪贴板上,并粘贴在客户端机器上的新文件中. 虽然可以直接用),以便通过SSH进行通信.

我们的目标是将连接到您的MySQL服务器的潜在途径的数量保持在最小限度上,虽然这个过程比直接传输文件更具劳动力,但它同样安全,不需要您在两台机器之间打开SSH连接。

首先,在您的非根用户的主目录中创建一个目录,在MySQL客户端上创建一个目录,称此目录为client-ssl:

1[environment third]
2mkdir ~/client-ssl

由于证书密钥敏感,请锁定该目录的访问,以便只有当前用户才能访问它:

1[environment third]
2chmod 700 ~/client-ssl

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

1[environment second]
2sudo cat /var/lib/mysql/ca.pem
1[secondary_label Output]
2[environment second]
3-----BEGIN CERTIFICATE-----
4
5. . .
6
7-----END CERTIFICATE-----

将整个输出,包括开始证书结束证书的行复制到剪辑板上。

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

1[environment third]
2nano ~/client-ssl/ca.pem

在内部,粘贴复制的证书内容从你的剪辑板. 保存和关闭文件,当你完成。

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

1[environment second]
2sudo cat /var/lib/mysql/client-cert.pem
1[secondary_label Output]
2[environment second]
3-----BEGIN CERTIFICATE-----
4
5. . .
6
7-----END CERTIFICATE-----

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

在客户端-ssl 目录中打开同名文件 MySQL 客户端 :

1[environment third]
2nano ~/client-ssl/client-cert.pem

将内容粘贴到您的剪辑板上. 保存并关闭文件。

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

1[environment second]
2sudo cat /var/lib/mysql/client-key.pem
1[secondary_label Output]
2[environment second]
3-----BEGIN RSA PRIVATE KEY-----
4
5. . .
6
7-----END RSA PRIVATE KEY-----

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

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

1[environment third]
2nano ~/client-ssl/client-key.pem

将内容粘贴到您的剪辑板上. 保存并关闭文件。

客户端机器现在拥有访问 MySQL 服务器所需的所有凭证,但是,MySQL 服务器尚未设置为客户端连接所需的可信证书。

若要更改此情况,请再次登录 MySQL 服务器上的 root 帐户:

1[environment second]
2mysql -u root -p

从这里,更改您的远程用户的安全要求。而不是要求SSL条款,应用要求X509条款. 这意味着要求SSL条款提供的所有安全性,但还要求连接客户端提供由MySQL服务器信任的证书授权机构签署的证书。

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

1[environment second]
2ALTER USER 'mysql_user'@'mysql_client_IP' REQUIRE X509;

然后清洗这些更改,以确保它们立即应用:

1[environment second]
2FLUSH PRIVILEGES;

离开后回到壳,当你完成:

1[environment second]
2exit

接下来,检查在连接时是否可以验证双方。

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

1[environment third]
2mysql -u mysql_user -p -h mysql_server_IP
1[secondary_label Output]
2[environment third]
3ERROR 1045 (28000): Access denied for user 'mysql_user'@'mysql_client_IP' (using password: YES)

正如预期的那样,当没有提供客户端证书时,服务器会拒绝连接。

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

1[environment third]
2mysql -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

您已向客户提供相应的证书和密钥,因此此尝试将成功:

1[environment third]

退出登录以重新访问您的 shell 会话:

1[environment third]
2exit

现在您已确认访问服务器,让我们实施一个小型的可用性改进,以避免每次连接时需要指定证书文件。

在 MySQL 客户端机上的主目录中,创建一个名为 `~/.my.cnf 的隐藏配置文件:

1[environment third]
2nano ~/.my.cnf

在文件的顶部,创建一个名为[客户端]的部分。下面,添加ssl-ca,ssl-certssl-key选项,并将它们指向您从服务器上复制的相应文件。

1[label ~/.my.cnf]
2[environment third]
3[client]
4ssl-ca = ~/client-ssl/ca.pem
5ssl-cert = ~/client-ssl/client-cert.pem
6ssl-key = ~/client-ssl/client-key.pem

" ssl-ca " 选项要求客户端核实MySQL服务器提交的证书是否由您指定的证书主管部门签署。 这使得客户端可以相信它正在连接到一个信任的MySQL服务器. 同样,sl-cert'和sl-key'选项指出,需要哪些文件向MySQL服务器证明,它也有同一证书当局签署的证书。 如果您希望 MySQL 服务器能够验证客户端是否也得到CA的信任,您需要这个.

保存并关闭文件,当你完成。

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

1[environment third]
2mysql -u remote_user -p -h mysql_server_ip

现在,您的客户端和服务器在谈判连接时都会呈现证书,每个方都配置为对其本地拥有的远程证书进行验证。

结论

您的 MySQL 服务器现在已配置为需要来自远程客户端的安全连接,此外,如果您遵循使用证书权限验证连接的步骤,则双方都建立了一定的信任级别,即远程客户端是合法的。

Published At
Categories with 技术
comments powered by Disqus