问题
我不知道如何强制 Postfix 使用 TLS 连接到 MySQL。我能以 postfix 用户身份手动使用 TLS 从 Postfix 服务器连接到 MySQL 服务器,因此 MySQL 身份验证没有任何问题。问题很明显:Postfix 没有为 MySQL 连接请求 TLS。
版本:
- 操作系统:CentOS 7
- 后缀:2:2.10.1-6.el7 和 2:3.2.4-1.gf.el7
- MySQL(MariaDB):5.5.56
我是如何来到这里的
我一直在网上搜索这个问题的答案,包括各种 StackExchange 网站。我反复阅读了 Postfix 和 MySQL 文档。我找到的最佳答案是我认为不必要的复杂答案:“在 Postfix 和 MySQL 服务器之间建立 SSH 隧道,然后通过它进行连接。“必须有一种方法可以指示 Postfix 与 MySQL 客户端使用 TLS(SSL)加密。
在我们探索设置之前,请允许我确认这一点: 我的邮件服务器设置即使没有 MySQL TLS 也能完美运行。我成功地将 TLS 用于 SMTPS 和 IMAPS,并且与我的问题无关。除了 Postfix 和 MySQL 服务器之间的 MySQL 连接未加密外,邮件在我的网络内外都安全传输。除了暴露的 Postfix-MySQL 链接外,我的邮件基础设施没有任何问题。
但是,由于安全要求不断变化,我必须更新现有基础架构以加密所有 MySQL 连接。为 MySQL 连接设置 TLS 很容易。 手动测试表明,MySQL 客户端可以通过 TLS 加密链接从所有允许的主机成功连接。因此,MySQL TLS 设置也很稳定,并且适用于所有情况除了 Postfix。
我尝试过的方法
Postfix服务器上相关配置:
/etc/postfix/main.cf简化为几个连接中的一个,以使材料尽可能的具体。
virtual_alias_maps = proxy:mysql:/etc/postfix/lookup_aliases.cf
proxy_read_maps = $virtual_alias_maps
/etc/postfix/lookup_aliases.cf
凭证和主机名被混淆。
hosts = mysql-server.domain.tld
user = postfix
password = *****
dbname = mail
option_file = /etc/my.cnf.d/client.cnf
option_group = client
tls_verify_cert = yes
query = SELECT goto FROM alias WHERE address = '%s' AND active = '1'
/etc/my.cnf
此文件未动。我将其包含进来只是为了表明下一个配置文件已正确包含在 MySQL 客户端配置中。
!includedir /etc/my.cnf.d
/etc/my.cnf.d/客户端.cnf
[client]
ssl = true
成功 -- 手动 -- 以 postfix 用户身份从 Postfix 服务器输出 MySQL TLS 连接
特别要注意的是,TLS 已成功使用:
# hostname -f
mail.domain.tld
# sudo -u postfix mysql -h mysql-server.domain.tld -u postfix -p mail
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 72
Server version: 5.5.56-MariaDB MariaDB Server
Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [mail]> \s
--------------
mysql Ver 15.1 Distrib 5.5.56-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 72
Current database: mail
Current user: [email protected]
SSL: Cipher in use is DHE-RSA-AES256-GCM-SHA384
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 5.5.56-MariaDB MariaDB Server
Protocol version: 10
Connection: mysql-server.domain.tld via TCP/IP
Server characterset: latin1
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Uptime: 1 hour 27 min 23 sec
Threads: 1 Questions: 271 Slow queries: 0 Opens: 13 Flush tables: 2 Open tables: 39 Queries per second avg: 0.051
--------------
MariaDB [mail]> \q
Bye
MySQL Server上的相关配置:
MySQL 资助请注意,TLS(SSL)是必需的,但在解决此 TLS 连接问题之前,权限相对宽松:
MariaDB [(none)]> SHOW GRANTS FOR 'postfix'@'10.0.101.%';
+-----------------------------------------------------------------------------------------------------+
| Grants for [email protected].% |
+-----------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'postfix'@'10.0.101.%' IDENTIFIED BY PASSWORD '*SOMEPASSWORDHASH' REQUIRE SSL |
| GRANT SELECT ON `mail`.* TO 'postfix'@'10.0.101.%' |
+-----------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
日志
当需要 SSL 时,Postfix 连接失败即使此处 MySQL TLS 连接的手动命令行测试成功,Postfix 仍然不会使用 MySQL TLS。
MySQL 常规日志:
180217 14:45:15 16 Connect [email protected] as anonymous on mail
16 Connect Access denied for user 'postfix'@'mail.domain.tld' (using password: YES)
Postfix 日志:
Feb 19 19:22:55 mail postfix/cleanup[11951]: warning: proxy:mysql:/etc/postfix/lookup_aliases.cf lookup error for "[email protected]"
Feb 19 19:22:55 mail postfix/cleanup[11951]: warning: E2CCA2069823: virtual_alias_maps map lookup problem for [email protected] -- message not accepted, try again later
当 REQUIRE SSL 被删除时,Postfix 连接成功
这是 Postfix 在将权限从 REQUIRE SSL 更改为 REQUIRE NONE 后成功连接的情况。但是,连接未加密。
180217 15:17:21 26 Connect [email protected] as anonymous on mail
26 Query show databases
26 Query show tables
26 Field List admin
26 Field List alias
26 Field List alias_domain
26 Field List config
26 Field List domain
26 Field List domain_admins
26 Field List fetchmail
26 Field List log
26 Field List mailbox
26 Field List quota
26 Field List quota2
26 Field List vacation
26 Field List vacation_notification
26 Query select @@version_comment limit 1
结论
我所需要的只是让 Postfix 遵守ssl = true
其 MySQL 客户端连接。如果您需要任何进一步的信息,请告诉我。
更新:
在提出这个问题后,我仔细阅读后发现,2.11 之前的 Postfix 版本根本不支持读取 MySQL 配置文件。因此,无法配置供应商提供的 Postfix 版本(2.10 版)以使用 MySQL TLS。我觉得 Postfix 文档中的措辞很糟糕,其中Postfix 文档中的 MySQL 配置内容如下:
Postfix 3.1 and earlier don't read [client] option group settings unless a non-empty option_file or option_group value are specified. To enable this, specify, for example "option_group = client".
作者未能阐明:
These options are ignored for Postfix 2.10 and earlier. Postfix 2.11 through 3.1 don't read [client] option group settings unless a non-empty option_file or option_group value are specified. To enable this, specify, for example "option_group = client".
因此,我将 CentOS 7 上的 Postfix 从供应商提供的 2.10 版本升级到了提供 GhettoForge Plus版本 3.2。我确实安装了附加postfix3-mysql
包。我曾寄予厚望,但希望落空了。现在,即使有了 Postfix 3.2,它仍然无法通过 TLS 链接连接到 MySQL。
我已经尝试了这两种方法option_file = /etc/my.cnf
(应该是默认的和不必要的),但option_file = /etc/my.cnf.d/client.cnf
都无济于事。
我甚至尝试通过添加 来强制 Postfix 考虑 TLS tls_verify_cert = yes
。这也没有任何效果。请注意,证书名称确实匹配,因此如果实际尝试,此验证将通过。
答案1
概要
为了从 Postfix 建立 MySQL TLS 连接,您需要:
- Postfix 2.11 或更高版本. CentOS 7 仅提供Postfix 版本 2.10。您必须从非 CentOS 方式获取 Postfix 升级。我选择使用
postfix3
来自postfix3-mysql
GhettoForge 升级版因为看起来受到 CentOS 社区的大力推荐。 - 放在您的
mysql_table
配置文件中任何一个:- 至少一个允许的
tls_ciphers
设置; - 客户端 TLS 证书及其匹配的私钥,由 MySQL 服务器和 Postfix 客户端共用的证书颁发机构签名; 或者
- 两个都。
- 至少一个允许的
- 不要依赖于 /etc/my.cnf 或 /etc/my.cnf.d/* 文件中的这些设置! Postfix MySQL 代码不会读取这些文件来确定是否建立 MySQL TLS 连接;它们解析得太晚了。仅有的促使 Postfix 打开 MySQL TLS 连接的方法是在
mysql_table
配置文件中指定 TLS 设置。就这样。
我是如何来到这里的
我最终决定通读 Postfix 3.2 源代码。src/global/dict_mysql.c 的第 653-658 行尤其有用。
最终解决方案
如果您想模拟的行为,您只需要在配置文件ssl = true
中添加类似于以下内容的一行:mysql_table
tls_ciphers = TLSv1.2
我们的配置要求只使用 TLS 1.2 - 并且早已在我们的 MySQL 服务器配置中强制执行,所以我没有自动想到在客户端上也强制执行它 - 但如果您的组织容忍较旧的密码,您可以自由添加其他密码。
请注意,我们完全乐意不使用客户端证书。我们使用其他方法来保护和主动监控我们的数据库连接;我们只是不想增加复杂性。
替代解决方案
如果您希望强制只有已知的、受信任的客户端连接到您的 MySQL 服务器(并且您无法通过其他策略执行机制(如严格的防火墙、严格的密码复杂性、密码轮换周期、连接审核等)来实现这一点),那么您也可以通过mysql_table
配置文件中的这些附加设置使用客户端证书:
tls_key_file = /path/to/private.key
tls_cert_file = /path/to/public.certificate
tls_CAfile = /path/to/common.CA.certificate # OR tls_CApath = /path/to/CA-and-intermediate-chain-certificates/
再次,在 /etc/my.cnf 或 /etc/my.cnf.d/* 中设置这些无济于事. 这些文件直到后连接类型(TLS 或非 TLS)已经决定。
如果您选择使用客户端证书,在服务器上强制执行! 你不要当您只想加密 MySQL 流量时,不需要客户端证书;相反,只需使用tls_ciphers
上面的替代方法即可。添加客户端证书使 MySQL 能够验证连接的客户端是否已知且受信任,但只有你告诉 MySQL 如何做!它不会猜测,仅依靠客户端和服务器之间共同 CA 的存在只是这个强大工具的部分实现。如果您对这个 MySQL 安全模型感兴趣,我至少找到了一个操作指南提供了如何使用客户端证书验证的良好示例。