介绍
MySQL 是世界上最流行的开源关系数据库管理系统. 虽然现代包管理器已经减少了启动和运行 MySQL 的一些摩擦, 但是在安装它之后还应该执行一些进一步的配置. 花费一些额外时间的最重要方面之一是安全性.
默认情况下, MySQL 配置为仅接受本地连接, 或者来自安装 MySQL 的同一台机器的连接. 如果您需要从远程位置访问 MySQL 数据库, 那么安全地执行此操作非常重要. 在本指南中, 我们将演示如何在 Ubuntu 18.04 上配置 MySQL 以接受使用 SSL/TLS 加密的远程连接.
准备
要遵循本教程, 您将需要两台 Ubuntu 16.04 服务器. 我们将使用一个作为 MySQL 服务器, 另一个作为客户端. 没有服务器的同学可以在这里购买, 不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验, 学会安装后在购买服务器.
在第一台机器上, 您应该安装并配置 MySQL 服务器. 按照我们的四步教你搭建保护 MySQL 服务器! 教程来安装和配置软件.
在第二台计算机上, 安装 MySQL 客户端软件包. 您可以通过输入以下内容来更新 apt 软件包索引并安装必要的软件:
- sudo apt-get update
- sudo apt-get install MySQL-client
当您的服务器和客户端准备就绪后, 请继续.
检查当前的 SSL / TLS 状态
在开始之前, 我们可以在 MySQL 服务器实例上检查 SSL / TLS 的当前状态.
使用 root 用户登录 MySQL 会话. 我们将使用 - h 指定 IPv4 本地环回接口, 以强制客户端与 TCP 连接. 这将允许我们检查 TCP 连接的 SSL 状态:
MySQL -u root -p -h 127.0.0.1
系统将提示您输入在安装过程中输入 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_openssl 和 have_ssl 变量都标记为 DISABLED. 这意味着 SSL 功能已编译到服务器中, 但尚未启用.
检查我们当前连接的状态以确认:
- \s
- --------------
- 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 尚未加密我们的链接
完成后关闭当前的 MySQL 会话:
exit
现在我们可以开始为 SSL 配置 MySQL 以保护我们的连接.
生成 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
将产生如下所示的输出:
- 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'
- -----
输入以下命令检查生成的文件:
- sudo find /var/lib/MySQL -name '*.pem' -ls
- 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<^>
最后一列显示生成的文件名. 并表示生成的文件具有正确的用户和组所有权.
这些文件是证书颁发机构 (以 "ca" 开头),MySQL 服务器进程(以 "server" 开头) 和 MySQL 客户端 (以 "client" 开头) 的密钥和证书对.
在 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%';
- +---------------+-----------------+
- | 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
- --------------
. . .
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. 因此对远程用户开放的唯一连接选项将使用 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
- 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
上面输出中的 "0.0.0.0" 表示 MySQL 正在侦听所有可用接口上的连接.
接下来, 我们需要通过防火墙允许 MySQL 连接. 输入以下内容创建:
- sudo ufw allow MySQL
- Rule added
- Rule added (v6)
远程连接尝试现在应该够到达我们的 MySQL 服务器.
配置远程 MySQL 用户
MySQL 服务器现在正在侦听远程连接, 但我们目前没有配置任何可以从外部计算机连接的用户. 以 root 用户身份登录 MySQL 开始:
MySQL -u root -p
在内部, 您可以使用 CREATE USER 命令创建新的远程用户. 我们将在用户规范的主机部分中使用客户端计算机的 IP 地址来限制与该计算机的连接. 对于将来关闭 require_secure_transport 选项的某些冗余, 我们还将在帐户创建期间指定此用户通过包含 REQUIRE SSL 子句来要求 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
- --------------
. . .
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
提示您输入密码后, 应拒绝您的连接:
ERROR 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
- -----BEGIN CERTIFICATE-----
. . .
- -----END CERTIFICATE-----
将整个输出 (包括 BEGIN CERTIFICATE 和 END CERTIFICATE 行) 复制到剪贴板.
在 MySQL 客户端上, 在新目录中创建一个具有相同名称的文件:
nano ~/client-ssl/ca.pem
在里面, 粘贴剪贴板中复制的证书内容. 完成后保存并关闭文件.
接下来, 在 MySQL 服务器上显示客户端证书:
- sudo cat /var/lib/MySQL/client-cert.pem
- -----BEGIN CERTIFICATE-----
. . .
- -----END CERTIFICATE-----
再次, 将内容复制到剪贴板.
在目录中的 MySQL 客户端上打开一个具有相同名称的 client-ssl 文件:
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 服务器所需的所有凭据. 接下来, 我们需要改变我们的远程用户.
需要来自可信 CA 的远程用户证书
目前, MySQL 客户端具有可用于在连接时向服务器提供其证书的文件. 但是, 服务器仍未设置为要求来自受信任 CA 的客户端证书.
要更改此设置, 请在 MySQL 服务器上再次登录 MySQL root 帐户:
MySQL -u root -p
接下来, 我们需要更改远程用户的要求. 我们需要应用 REQUIRE X509 而不是 REQUIRE SSL . 这意味着前一个要求提供的所有安全性, 但另外要求连接客户端提供由 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
- ERROR 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 客户端计算机上的主目录中, 创建一个名为 nano ~/.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 服务器现在配置为需要来自远程客户端的安全连接. 此外, 如果您按照以下步骤使用证书颁发机构验证连接, 则双方将建立某种程度的信任, 即远程方是合法的.
来源: http://www.linuxidc.com/Linux/2019-05/158789.htm