MariaDB over SSL 不工作,“证书验证失败”

Posted

技术标签:

【中文标题】MariaDB over SSL 不工作,“证书验证失败”【英文标题】:MariaDB over SSL not working, "certificate verify failed" 【发布时间】:2017-06-28 00:10:25 【问题描述】:

使用this guide 我正在尝试设置 MariaDB (mysql) 以在 dbserverappclient 之间使用 SSL。

根据指南,我在服务器上创建了服务器和客户端证书。然后我将三个必要的客户端文件复制到 appclient 并设置所有权和权限:

[root@appclient mysql]# ll /etc/pki/tls/certs/
drwxr-xr-x. 2 mysql mysql   88 Feb  9 13:31 mysql

[root@appclient mysql]# ll /etc/pki/tls/certs/mysql/
-rw-------. 1 mysql mysql 1372 Feb  9 13:31 ca-cert.pem
-rw-------. 1 mysql mysql 1230 Feb  9 14:16 client-cert.pem
-rw-------. 1 mysql mysql 1705 Feb  9 14:16 client-key.pem

这是 appclient 上完整的 my.cnf:

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0

[client]
ssl-ca=/etc/pki/tls/certs/mysql/ca-cert.pem
ssl-cert=/etc/pki/tls/certs/mysql/client-cert.pem
ssl-key=/etc/pki/tls/certs/mysql/client-key.pem

[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid

!includedir /etc/my.cnf.d

接下来,我测试了 dbserver 上的 3306 端口是开放的:

[root@appclient mysql]# telnet dbserver 3306
Connected to dbserver.
Escape character is '^]'.
R
5.5.52-MariaDB

接下来我检查了 dbserver 上的 MariaDB (mysql) ssl 变量:

MariaDB [(none)]> show variables like '%ssl%';
+---------------+------------------------------------------+
| Variable_name | Value                                    |
+---------------+------------------------------------------+
| have_openssl  | YES                                      |
| have_ssl      | YES                                      |
| ssl_ca        | /etc/pki/tls/certs/mysql/ca-cert.pem     |
| ssl_capath    |                                          |
| ssl_cert      | /etc/pki/tls/certs/mysql/server-cert.pem |
| ssl_cipher    |                                          |
| ssl_key       | /etc/pki/tls/certs/mysql/server-key.pem  |
+---------------+------------------------------------------+

接下来我检查了 appclient 上的 MariaDB (mysql) ssl 变量:

MariaDB [(none)]> show variables LIKE '%ssl%';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| have_openssl  | DISABLED |
| have_ssl      | DISABLED |
| ssl_ca        |          |
| ssl_capath    |          |
| ssl_cert      |          |
| ssl_cipher    |          |
| ssl_key       |          |
+---------------+----------+
7 rows in set (0.00 sec)

这看起来像是问题的开始/根源。

如果我尝试从 appclient 连接到 dbserver

[root@appclient mysql]# mysql -h dbserver -u ssluser -p 
Enter password: 
ERROR 2026 (HY000): SSL connection error: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

没有布宜诺。

正在使用 openssl 检查 appclient 的证书...

[root@appclient mysql]# cd /etc/pki/tls/certs/mysql/
[root@appclient mysql]# openssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem
Error opening certificate file server-cert.pem
139864320337824:error:02001002:system library:fopen:No such file or directory:bss_file.c:398:fopen('server-cert.pem','r')
139864320337824:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:400:
unable to load certificate
client-cert.pem: OK

为了好玩,我在 dbserver 上运行了相同的 openssl 测试:

[root@dbserver mysql]# openssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem
server-cert.pem: C = XX, ST = XX, L = CityName, O = MyOrganization, OU = MyGroup, CN = dbserver
error 18 at 0 depth lookup:self signed certificate
OK
client-cert.pem: OK

本教程仅提到将ca-cert.pemclient-cert.pemclient-key.pem 复制到客户端,但上述故障表明客户端缺少server-cert.pem

我还需要在客户端上创建 server-*.pem 文件吗?如果是这样,这些在/etc/my.cnf 文件中的什么位置?

【问题讨论】:

那是自签名证书吗?由于 openssl 告诉您证书验证失败,这表明您用于签署证书的权限应该添加到您正在运行的操作系统中。我不知道是否有禁止验证证书的标志,也许在这个方向上搜索一下可能会有所帮助? 它是自签名的。所有证书都是根据文档在 dbserver 上生成的。请注意,由于缺少 server-cert.pem,openssl 未能通过测试,本教程中未对此进行描述或解决。这就是我坚持的部分。 cat server-cert.pem client-cert.pem > ca.pem 取得了一点进展,然后更新 appclient 的 my.cnf 以使用 ssl-ca=ca.pem。我收到的是身份验证错误,而不是 SSL 错误。 整理好了。编写了完整的 MariaDB/SSL 操作指南,并在下面作为答案发布。 嗯,很少看到如此详尽的问题和更详细的答案。干得好,我 +1! 【参考方案1】:

MySQL/MariaDB SSL 设置指南中缺少的部分是确保ssl-ca 证书文件同时包含服务器和客户端ca。

这是一个对我有用的分步指南:


这个答案假设有两台服务器:

    dbserver(我们的数据库所在的位置) appclient(我们的应用程序所在的位置)

FWIW,两台服务器都执行 SELinux。

首先,登录dbserver

为创建证书创建一个临时目录。

mkdir /root/certs/mysql/ && cd /root/certs/mysql/

创建服务器证书

openssl genrsa 2048 > ca-key.pem
openssl req -sha1 -new -x509 -nodes -days 3650 -key ca-key.pem > ca-cert.pem
openssl req -sha1 -newkey rsa:2048 -days 730 -nodes -keyout server-key.pem > server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -sha1 -req -in server-req.pem -days 730  -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem

将服务器证书移动到/etc/pki/tls/certs/mysql/ 目录路径假定为 CentOS 或 RHEL(根据需要调整其他发行版):

mkdir /etc/pki/tls/certs/mysql/
cp /root/certs/mysql/* /etc/pki/tls/certs/mysql/

请务必设置文件夹和文件的权限。 mysql 需要完全的所有权和访问权。

chown -R mysql:mysql /etc/pki/tls/certs/mysql

现在配置 MySQL/MariaDB

# vi /etc/my.cnf
# i
[mysqld]
bind-address=*
ssl-ca=/etc/pki/tls/certs/ca-cert.pem
ssl-cert=/etc/pki/tls/certs/server-cert.pem
ssl-key=/etc/pki/tls/certs/server-key.pem
# :wq 

然后

systemctl restart mariadb

不要忘记打开防火墙以允许来自 appclient 的连接(使用 IP 1.2.3.4)

firewall-cmd --zone=drop --permanent --add-rich-rule 'rule family="ipv4" source address="1.2.3.4" service name="mysql" accept'
# I force everything to the drop zone.  Season the above command to taste.

现在重启firewalld

service firewalld restart

接下来,登录dbserver的mysql服务器:

mysql -uroot -p 

发出以下命令为客户端创建用户。注意 GRANT 语句中的 REQUIRE SSL。

GRANT ALL PRIVILEGES ON *.* TO ‘iamsecure’@’appclient’ IDENTIFIED BY ‘dingdingding’ REQUIRE SSL;
FLUSH PRIVILEGES; 
# quit mysql

从第一步开始,您应该仍然在 /root/certs/mysql 中。如果没有,请 cd 回到它以执行以下命令之一。

创建客户端证书

openssl req -sha1 -newkey rsa:2048 -days 730 -nodes -keyout client-key.pem > client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -sha1 -req -in client-req.pem -days 730 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem

注意:我为服务器和客户端证书使用了相同的通用名称。 YMMV。

确保你仍然是 /root/certs/mysql/ 下一个命令

将服务器和客户端 CA 证书合并到一个文件中:

cat server-cert.pem client-cert.pem > ca.pem

确保您看到两个证书:

cat ca.pem 

服务器端工作暂时结束。

打开另一个终端并

ssh appclient

和以前一样,为客户端证书创建一个永久主页

mkdir /etc/pki/tls/certs/mysql/

现在,将客户端证书(在 dbserver 上创建)放在 appclient 上。 您可以 scp 覆盖它们,也可以一个一个地复制和粘贴文件。

scp dbserver
# copy files from dbserver to appclient
# exit scp

同样,请务必设置文件夹和文件的权限。 mysql 需要完全的所有权和访问权。

chown -R mysql:mysql /etc/pki/tls/certs/mysql

你应该有三个文件,每个文件都由用户 mysql 拥有:

/etc/pki/tls/certs/mysql/ca.pem
/etc/pki/tls/certs/mysql/client-cert.pem
/etc/pki/tls/certs/mysql/client-key.pem

现在在 [client] 部分编辑 appclient 的 MariaDB/MySQL 配置。

vi /etc/my.cnf
# i
[client]
ssl-ca=/etc/pki/tls/certs/mysql/ca.pem
ssl-cert=/etc/pki/tls/certs/mysql/client-cert.pem
ssl-key=/etc/pki/tls/certs/mysql/client-key.pem
# :wq 

重启appclient的mariadb服务:

systemctl restart mariadb

这里还在客户端

这应该返回:ssl TRUE

mysql --ssl --help

现在,登录appclient的mysql实例

mysql -uroot -p

下面的两个变量都应该是 YES

show variables LIKE '%ssl';
    have_openssl    YES
    have_ssl              YES

最初看到

 have_openssl NO

快速查看 mariadb.log 发现:

SSL 错误:无法从中获取证书 '/etc/pki/tls/certs/mysql/client-cert.pem'

问题是 root 拥有 client-cert.pem 和包含的文件夹。 解决方案是将 /etc/pki/tls/certs/mysql/ 的所有权设置为 mysql。

chown -R mysql:mysql /etc/pki/tls/certs/mysql

如果需要,从上面的步骤重新启动 mariadb

现在我们已准备好测试安全连接

我们还在 appclient 上

尝试使用上面创建的帐户连接到 dbserver 的 mysql 实例。

mysql -h dbserver -u iamsecure -p
# enter password dingdingding (hopefully you changed that to something else)

如果运气好的话,您应该可以正确登录。

要确认您已启用 SSL 连接,请从 MariaDB/MySQL 提示符发出以下命令:

\s 

这是一个反斜杠,也就是状态

这将显示您的连接状态,应该如下所示:

Connection id:      4
Current database:   
Current user:       iamsecure@appclient
SSL:            Cipher in use is DHE-RSA-AES256-GCM-SHA384
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server:         MariaDB
Server version:     5.X.X-MariaDB MariaDB Server
Protocol version:   10
Connection:     dbserver via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
TCP port:       3306
Uptime:         42 min 13 sec

如果您在尝试连接时遇到权限被拒绝错误,请检查上面的 GRANT 语句以确保没有任何杂散字符或 ' 标记。

如果您遇到 SSL 错误,请返回本指南以确保步骤有序。

这适用于 RHEL7,也可能适用于 CentOS7。无法确认这些确切步骤是否适用于其他地方。

希望这可以为其他人节省一点时间和麻烦。

【讨论】:

这些指南一直让我困惑的是为什么客户端需要服务器的密钥或任何证书。 TLS 证书的全部意义不在于证明服务器身份吗?【参考方案2】:

根据mentioned guide,您必须确保所有三个证书的“通用名称”都不同。

我遇到了同样的错误,因为我对所有三个证书都使用了相同的 CN。使用不同的 CN 重新生成证书后,错误消失了。

【讨论】:

CentOS 7 上的 MariaDB:可以确认这一点。使用 FQ 主机名作为 CN 后它失败了,但是当使用 Vivek 明确标记的建议时它工作得很好,一旦会话开始它正确地报告使用 SSL 密码(状态查询)。

以上是关于MariaDB over SSL 不工作,“证书验证失败”的主要内容,如果未能解决你的问题,请参考以下文章

Google DataStudio SSL 连接到 MariaDB

MariaDB 查询 SUM() OVER (PARTITION BY)

mysql/mariadb基于ssl的主从复制

使用带有 --ssl 的 PHP PDO 连接到 MySQL/MariaDB,无需证书

手机H5唤起支付宝APP钱包付款之证书验签

javax.net.ssl.SSLHandshakeException 通过 Cajo over SSL 连接时出现问题