MariaDB over SSL 不工作,"certificate verify failed"

MariaDB over SSL not working, "certificate verify failed"

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

我按照指南在服务器上创建了服务器和客户端证书。然后我将三个必要的客户端文件复制到 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)

这看起来像问题的 start/source。

如果我尝试从 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 文件中的什么位置?

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

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


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

  1. dbserver(我们的数据库所在的位置)
  2. appclient(我们的应用程序所在的地方)

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

首先,登录数据库服务器

创建用于创建证书的临时目录。

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

这里还是客户端

这应该 return: 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 error: Unable to get certificate from '/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 

这是一个反斜杠 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。无法确认这些具体步骤是否适用于其他地方。

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

根据 mentioned guide,您必须确保所有三个证书的 "Common name" 都不同。

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