可以请求 postfix 从数据库获取其中继服务器的 sasl 登录信息。然后我让此中继服务器获取相同的登录信息。
我们如何格式化这个配置文件以便正确获取?
我们知道这些信息:
- 中继的域名。
- 邮箱的用户名。
- Postfix 服务器上的域名(可能有多个)。
现在,仅包含密码的纯文本文件将被格式化如下(每行),假设使用密码mailbox
发送:domain2
mailpass
smtp.relay.tld [email protected]:mailpass
我验证了纯文本文件方法适用于数据库中的特定用户和密码。现在我想使用 .cf 文件连接数据库。
给定一个域表如下1:
+----+----------+-------------+----------+
| id | username | domain | password |
+----+----------+-------------+----------+
| 1 | mailbox | domain2.tld | mailpass |
+----+----------+-------------+----------+
一般来说,这样的文件的格式如下;
user = sqluser
password = dbpass
hosts = localhost
dbname = maildb
query = SELECT password FROM accounts WHERE username = '%u' AND domain = '%d'
我不确定“查询”参数中到底要放什么。官方文档对此非常糟糕:它声明可以使用 SQL 数据库进行配置,但根本没有说明如何配置,也没有给出具体示例。
现在我尝试使用简单的方法;创建一个查询,该查询仅返回与纯文本文件中的行完全相同的值。我还尝试返回该行的各种子集,但没有成功。每次尝试都只会生成“访问被拒绝”错误。
1:我知道以这种方式将实际用户的密码存储在数据库中是一种馊主意。这里使用的密码仅仅是为了两个特定服务器之间的通信。
想要使用数据库的原因是可移植性和可扩展性的结合。例如,当且仅当某个域想要使用多个邮件服务器,或者迁移到另一个电子邮件提供商时。不只使用一个密码的原因是为了能够区分关注点(每个用户都配置了一个单独的中继密码,他们自己并不知道,但每个邮件服务器上的 postfix 用户通过查看某个数据库表知道该密码。这是一种与 openstack keystone 相当的机制,但复杂程度要低得多)。
进一步挖掘:启用 L4 级日志记录并查看服务器的连接记录,它似乎从未发送过 AUTH 消息(因此它甚至没有弄清楚如何“找到”用户)。可以在邮件日志中找到以下消息(域名等已删除);
postfix/smtp[6494]: maps_find: smtp_sasl_password_maps: smtp.relay.tld: not found
postfix/smtp[6494]: maps_find: smtp_sasl_password_maps: smtp.relay.tld:587: not found
postfix/smtp[6494]: smtp_sasl_passwd_lookup: no auth info found
(sender=`[email protected]', host=`smtp.relay.tld')
但是,执行这个命令:
postmap -q [email protected] mysql:/etc/postfix/mysql-map.cf
生产
smtp.relay.tld [email protected]:mailpass
换句话说,配置是有效的,但是后缀程序正在执行一些奇怪的查询以便从数据库中获取密码,并且没有指定实际上是什么,也没有记录。
答案1
有两件事是必要的:
首先,smtp_sender_dependent_authentication = yes
必须在 postfix 主配置文件中启用该选项(通常位于/etc/postfix/main.cf
)。如果没有此选项,服务器将仅根据中继主机的域名进行搜索,该域名对于每个用户都相同。
其次,正确的查询应该是这样的:
query = SELECT CONCAT(username, "@", domain, ":", password) FROM accounts \
WHERE username = '%u' AND domain = '%d'
注意:配置文件不支持这种方式的多行;因此删除 \ 和换行符
答案2
只是在这里做一个大胆的猜测(我没有混合 Postfix 和 SQL),但我将从以下内容开始:
电子邮件地址的“本地部分”不会自动成为中继身份验证的“用户名”。因此,即使在你的数据库中它们都是相同的,Postfix 无法自动做出这种假设,因此用户名字段无论如何都必须归还。
所有 Postfix 表都以相同的方式执行查找:一个输入产生一个输出,并且 Postfix 核心实际上并不关心特定表后端是否支持多列。我认为它需要单个字符串并在所有情况下以相同的方式解析它。
根据第2点,如果纯文本表存储[email protected]:mailpass
,那么SQL查询应该可能还返回以相同方式格式化的单个列。所以我会尝试这样做:
query = SELECT CONCAT(username, ":", password) FROM accounts WHERE username = '%u' AND domain = '%d'
但如果这不正确,那么应该使用两个单独的列:
query = SELECT username, password FROM accounts WHERE username = '%u' AND domain = '%d'