目录
- 简介
- 使用 TLSRPT 支持构建 Postfix
- 启用 TLSRPT
- 连接复用与会话恢复
- TLSRPT 状态日志记录
- 通过电子邮件发送 TLSRPT 摘要
- 通过 smtp_tls_policy_maps 支持 MTA-STS
- 限制
- 致谢 ;
简介 ;
TLSRPT 协议在 RFC 8460 中定义。通过此协议,一个电子邮件接收域可以在 DNS 中发布一项策略,并请求每天汇总成功和失败的 SMTP over TLS 连接到该域的 MX 主机的报告。对 TLSRPT 的支持在 Postfix 3.10 中添加。
对于域 example.com,策略可能如下所示:
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:[email protected]"
政策可将 mailto: 替换为 https: 目标。
下图展示了 Postfix TLS 握手事件(成功或失败)如何被收集并处理为每日汇总报告。
Postfix SMTP 和 TLS 客户端引擎 → ; TLSRPT 客户端库 (链接到 Postfix) → ; TLSRPT 收集器、获取器和摘要生成器 → ; 电子邮件或 HTTP 交付
- Postfix SMTP 和 TLS 客户端引擎将为每个 TLS 握手生成一个"成功"或"失败"事件,
- 它们将这些事件传递给一个内置的 TLSRPT 客户端库,该库通过本地套接字发送数据到
- 每个 Postfix 机器上运行的本地 TLSRPT 收集器。一个 TLSRPT 获取器从各个收集器中收集信息,一个中央 TLSRPT 报告生成器生成每日汇总报告。
TLSRPT 客户端库以及用于收集、获取和报告 TLSRPT 信息的基础设施,由 sys4 在 https://github.com/sys4/libtlsrpt 和 https://github. com/sys4/tlsrpt-reporter。
Postfix 实现支持带有 DANE(Postfix 内置)和 MTA-STS(通过 smtp_tls_policy_maps 插件)的域的 TLSRPT。
Postfix smtp(8) 客户端进程实现了 SMTP 客户端引擎。当 "smtp_tls_connection_reuse = no",smtp(8) 客户端进程还实现 TLS 客户端引擎。当设置为 "smtp_tls_connection_reuse = yes" 时,smtp(8) 客户端进程将 TLS 处理委托给 Postfix 的 tlsproxy(8) 进程。无论哪种方式,Postfix 都会生成完全相同的 TLSRPT 事件。
构建支持 TLSRPT 的 Postfix ;
这些说明假设您已按照 INSTALL 文档从源代码构建 Postfix。如果您从供应商特定的源代码包构建 Postfix,可能需要进行一些修改。
Postfix TLSRPT 客户端依赖于 TLSRPT 库,该库可能以构建包(如 rpm、deb 等)形式提供,或可从源代码构建:
该库通常作为头文件安装在 /usr/local/include/tlsrpt.h,对象库安装在 /usr/local/lib/libtlsrpt.a 或 /usr/local/lib/libtlsrpt.so。实际路径名取决于操作系统平台规范。
为了构建支持 TLSRPT 的 Postfix,您需要添加编译器选项 -DUSE_TLSRPT(以启用 TLSRPT 支持)和 -I(指向包含 tlsrpt.h 头文件的目录),并需要添加链接器选项以链接 TLSRPT 客户端库,例如:
make -f Makefile.init makefiles \ "CCARGS=-DUSE_TLSRPT -I/usr/local/include" \ "AUXLIBS=-L/usr/local/lib -Wl,-rpath,/usr/local/lib -ltlsrpt"
(在 Solaris 系统上,您可能需要使用 "-Wl,-R" 代替 "-Wl,-rpath"。)
然后,只需运行 'make'。
注意:如果您的构建命令行已经包含 CCARGS 或 AUXLIBS 设置,则只需将上述设置附加到现有的 CCARGS 或 AUXLIBS 值后:
make -f Makefile.init makefiles \ "CCARGS=... -DUSE_TLSRPT -I/usr/local/include" \ "AUXLIBS=... -L/usr/local/lib -Wl,-rpath,/usr/local/lib -ltlsrpt"
启用 TLSRPT ;
安装 Postfix TLSRPT 支持后,您可以在 main.cf 中像这样启用 TLSRPT 支持:
smtp_tlsrpt_enable = yes smtp_tlsrpt_socket_name = 路径/到/socket
smtp_tlsrpt_socket_name 参数指定一个绝对路径名,或相对于 $queue_directory 的路径名。
注意事项:
- 推荐的套接字位置尚未确定。一个良好的套接字位置应位于 Postfix 队列目录下,例如: "smtp_tlsrpt_socket_name = run/tlsrpt/tlsrpt.sock"。使用相对路径的优势在于,无论 Postfix 是否启用 chroot 环境,均可正常工作。
- 无论 Postfix 是否启用 chroot 环境,TLSRPT 接收程序(tlsrpt_collectd)均需配置为使用套接字的绝对路径名。
- 请勿在 Postfix 套接字目录(如 private 或 public)下指定 TLSRPT 套接字位置。仅 Postfix 程序应在此处创建套接字。
有关如何运行 TLSRPT 收集和报告基础设施的详细信息,请参阅文档 https://github.com/sys4/tlsrpt-reporter。
连接复用与会话恢复 ;
Postfix SMTP 客户端实现了两种类型的复用:
- SMTP 连接复用:Postfix SMTP 客户端创建一个新的 SMTP 连接,发送一封电子邮件,然后保存该连接而非关闭它。之后,某个 SMTP 客户端会复用该连接,发送电子邮件,并根据是否达到复用限制来保存或关闭连接。每个连接一次只能被一个 Postfix SMTP 客户端使用。
TLS 会话恢复:Postfix SMTP 客户端保存"新"TLS 握手结果。之后,一个或多个 SMTP 客户端创建新的 SMTP 连接,并在新连接上恢复保存的 TLS 会话。
;
当然还有第三种情况:
结合重用和恢复:Postfix SMTP 客户端创建一个新的 SMTP 连接,发送一封电子邮件,保存"新"TLS 握手结果,并保存连接而非关闭它。随后,一个 SMTP 客户端依次复用(并保存)该连接,而一个或多个客户端创建新的 SMTP 连接,并在新连接上恢复保存的 TLS 会话。
;
在所有情况下,当重新使用保存的 SMTP 连接时不会进行 TLS 握手,当恢复保存的 TLS 会话时也不会进行"新的"TLS 握手。
如下一节所述,Postfix 默认仅对"新的"TLS 握手记录并生成 TLSRPT 事件。
TLSRPT 状态日志记录 ;
启用 TLSRPT 支持后,Postfix TLSRPT 客户端不仅会将事件报告给一个不可见的每日成功/失败汇总队列,还会将可见记录日志记录到邮件日志文件中。
以下是 Postfix SMTP 客户端或 tlsproxy 守护进程的日志记录示例:
TLSRPT: status=success, domain=example.com, receiving_mx=mail.example.com[ipaddr] ; TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr], failure_type=starttls_not_supported ; TLSRPT: status=failure, domain=example.net, receiving_mx=mail.example.net[ipaddr], failure_type=validation_failure, failure_reason=self-signed_certificate
注意事项:
Postfix 仅在新的 SMTP 连接上进行 TLS 握手时记录并报告 TLSRPT 状态。当 SMTP 连接被重用时,不会进行 TLS 握手,因此不会记录 TLSRPT 状态。此类连接的 Postfix SMTP 客户端日志如下:
已验证 TLS 连接被重用 到 mail.example.com[ipaddr]:25: TLSv1.2 使用加密套件 ECDHE-RSA-AES256-GCM-SHA384 (256/256 位) ; 未受信任的 TLS 连接被重复使用 到 mail.example.com[ipaddr]:25: TLSv1.2 使用加密套件 ECDHE-RSA-AES256-GCM-SHA384 (256/256 位)
- 默认情况下,Postfix 不会报告 TLS 握手过程中复用先前协商的 TLS 会话的 TLSRPT 状态(因为没有新的信息可报告)。指定 "smtp_tlsrpt_skip_reused_handshakes = no" 以报告所有 TLS 握手操作的 TLSRPT 状态。这在故障排除时可能有用。
Postfix 日志记录中证书验证失败的信息可能因新会话或重复使用会话而有所不同。
新 TLS 会话:
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr], failure_type=validation_failure, failure_reason=self-signed_certificate
已重用 TLS 会话:
mail.example.org[ipaddr]:25: re-using session with untrusted peer 凭据,请查看日志中较早的记录 TLSRPT: 状态=失败, 域名=example.org, 接收MX=mail.example.org[ipaddr], 失败类型=证书未受信任
日志记录可能不同,因为重用的TLS会话不包含TLS身份验证失败的详细信息。
通过电子邮件发送 TLSRPT 摘要
RFC 8460 第 3 节 规定,邮件传输代理(MTA)在通过电子邮件发送失败报告时不得强制执行 TLS 安全。
选项:
- 在电子邮件报告中,指定消息头"TLS-Required: no",该头在RFC 8689,将 Postfix SMTP 客户端的 TLS 安全级别降低为 "may"(即不验证远程 SMTP 服务器证书,并在 TLS 不可用时回退到明文传输)。 ;
此功能在 Postfix 3.10 及更高版本中可用。如果您的外发 MTA 运行的是较旧版本,您可以使用下面描述的选项之一。 - 不采取任何行动。当 TLS 安全强制执行被要求但失败时,TLSRPT 摘要消息将被延迟,直到问题得到解决,或消息在邮件队列中过期。请注意,TLSRPT 不是实时监控服务;平均需要 12 小时才能通过 TLSRPT 报告故障。
对于不支持"TLS-Required: no"标头功能的出站 MTA(如 Postfix 3.9 及更早版本),请禁用 TLSRPT 摘要发送者的 TLS 安全强制执行。在出站 MTA 实例上实施以下配置(将 [email protected] 替换为实际报告生成器的发送地址):
/etc/postfix/main.cf: # 限制:此设置会被 transport_maps 覆盖。 sender_dependent_default_transport_maps = inline:{ { [email protected] = 允许明文 } } ; /etc/postfix/master.cf: # 服务名称 类型 权限 是否受限 启动方式 最大进程数 命令 allow-plaintext unix - - - - - smtp -o { smtp_tls_security_level = may } -o { smtp_tls_policy_maps = static:may }
通过 smtp_tls_policy_maps 支持 MTA-STS
Postfix 通过 smtp_tls_policy_maps 策略插件支持 MTA-STS,该插件会返回 TLS 安全级别及包含证书匹配要求的 name=value 属性。Postfix 3.10 及更高版本扩展了策略插件的响应,添加了 TLSRPT 所需的额外 name=value 属性。
支持 MTA-STS 的 smtp_tls_policy_maps 插件示例包括:
- postfix-tlspol,支持使用 Postfix 内置 DANE 的域,以及支持 MTA-STS 的域。
- postfix-mta-sts-resolver,自 1.5.0 版本(2025 年 2 月)起支持 MTA-STS。
这两个插件均可生成 Postfix 支持 TLSRPT 所需的额外 name=value 属性(截至 2025 年 2 月)。此功能通过在插件配置文件中设置 tlsrpt 布尔值启用。此设置在 Postfix 3.10 及更高版本中是安全的,即使 Postfix TLSRPT 支持在构建时或运行时被禁用。Postfix 3.9 及更早版本会报告一个策略错误,提示 "无效属性名称"。
下文中的示例适用于RFC 8461 第3.2节中给出的此MTA-STS策略示例:
version: STSv1 mode: enforce mx: mail.example.com mx: *.example.net mx: backupmx.example.com max_age: 604800
支持的属性列表如下。当值可能包含空格时,请使用 { name = value } 代替 name=value。策略响应可能包含换行符。
policy_type=type ;
指定 sts 或 no-policy-found。
示例:policy_type=sts
policy_domain=name ;
MTA-STS 策略适用的域。
示例:policy_domain=example.com
{ policy_string = value } ;
为每个 MTA-STS 策略功能指定一个 policy_string 实例,用 "{" 和 "}" 包围以保护属性值中的空格。
;
示例:{ policy_string = version: STSv1 } { policy_string = mode: enforce } ...
上述格式忽略开头 "{" 后的空格、等号 "=" 周围的空格以及闭合 "}" 前的空格。
mx_host_pattern=pattern ;
为 MTA-STS 策略中的每个 "mx:" 特征指定一个 mx_host_pattern 实例。
示例:mx_host_pattern=mail.example.com mx_host_pattern=*.example.net ...
policy_failure=type ;
如果指定,则强制 MTA-STS 策略执行失败,并显示指定的错误,即使服务器证书满足常规 PKI 约束。有效的错误包括 sts-policy-fetch-error, sts-policy-invalid, sts-webpki-invalid 或更不具体的 validation-failure。
示例:policy_failure=sts-webpki-invalid
policy_ttl=time (已废弃)
此属性已废弃。time 值不再使用,且对该属性的支持最终将从代码中移除。
注意事项:
- Postfix 3.10 及更高版本将在 MTA-STS 响应中接受这些额外属性,即使 Postfix TLSRPT 支持在构建时或运行时被禁用。当 Postfix TLSRPT 支持被禁用时,Postfix 仍可能使用 policy_failure 属性,并忽略仅用于 TLSRPT 的属性。
- 为非 STS 策略指定这些属性是错误的。
限制
Postfix TLSRPT 实现仅报告 TLS 握手成功或失败。它不会报告连接失败,或在 TLS 握手前后断开的连接。
Postfix TLSRPT 实现每个 SMTP 连接最多报告一次最终 TLS 握手状态('成功' 或 '失败')。Postfix TLSRPT 不会在报告可恢复失败后,再为同一连接报告最终状态为 '成功'。原因是过滤 TLS 错误并从 TLS 引擎将错误详细信息回传给 SMTP 协议引擎过于复杂。这并非 Postfix 的内部工作方式。
致谢 ;
- TLSRPT 客户端库以及用于收集、获取和报告 TLSRPT 信息的基礎设施由 sys4 实现并维护。