MTA-STS 多域名策略编排:Wildcard MX 兼容性与 TLS-RPT 联动

面向多域名邮件环境,详解 MTA-STS 策略编排模型、Wildcard MX 场景兼容、TLS-RPT 报告聚合与告警联动策略。

1. 引言

RFC 8461 定义的 MTA-STS(SMTP MTA Strict Transport Security)通过 DNS TXT 记录发布策略标识,再通过 HTTPS 获取 JSON 格式的策略文件,使发送方 MTA 在连接接收方时强制要求 TLS 证书验证[1]。单域名场景的部署已较为成熟,但当企业运营数十乃至数百个域名(品牌域名、子公司域名、营销域名等),且这些域名共享一组 MX 服务器时,策略编排、缓存一致性与故障隔离就变得复杂。

此外,Wildcard MX 记录(如 *.mail.example.com)在 MTA-STS 模式下的兼容性并非直接适用,需要仔细设计 mx: 字段的匹配逻辑。而 TLS-RPT (RFC 8460) 作为传输安全报告机制,将所有失败事件推送到指定邮箱——多域名场景下,区分是哪个域名的策略配置导致了故障,是运维的关键挑战[2]。

本文聚焦多域名 MTA-STS 的架构级问题:策略合并/分发模型、Wildcard MX 的处理、TLS-RPT 的多域报告解析与告警阈值,以及 max_age 的编排策略。

2. MTA-STS 策略基础回顾

MTA-STS 采用二层发现机制:

发送方 MTA 根据 DNS 发现启用 MTA-STS 后,缓存 HTTPS 策略并在 max_age 秒内以此策略发起 TLS 连接。若连接失败,行为由 mode 决定——testing 仅记录、enforce 拒绝投递、none 关闭检查[1]。

RFC 8461 规定每个域名需要独立的 DNS TXT 记录和独立的 HTTPS 策略文件。这意味着驾驭 100 个域名的企业需要 100 条 TXT 记录和 100 个策略 JSON——但这个复杂度可以通过共享策略模式降低。

3. 多域名策略编排模型

3.1 独立策略模型(标准推荐)

每个域名维护独立的 _mta-sts.TLD.txt 和独立的策略 JSON。这是 RFC 8461 的默认路径,优势在于故障隔离性最优——一个域名的证书过期不影响其他域名。但运维成本随域名数量线性增长。

# 域名 A
_mta-sts.a.example.com.  TXT "v=STSv1; id=2026072401;"
# HTTPS: https://mta-sts.a.example.com/.well-known/mta-sts.txt
# {"version":"STSv1","mode":"enforce","mx":"mx-a.example.com","max_age":86400}

# 域名 B
_mta-sts.b.example.com.  TXT "v=STSv1; id=2026072401;"
# HTTPS: https://mta-sts.b.example.com/.well-known/mta-sts.txt
# {"version":"STSv1","mode":"enforce","mx":"mx-b.example.com","max_age":86400}

适用场景:各域名拥有独立的 MX 服务器或独立的证书名(CN/SAN)。

3.2 共享策略模型(共享 MX)

当多个域名指向同一组 MX 服务器(如 mx.central.example),可以将这些域名的 mta-sts 子域名指向同一个 HTTPS 端点,节省策略文件数量。通过反向代理或 CDN 实现单策略多域共享。

# 所有域名的 _mta-sts 指向同一个 HTTPS 服务器
_mta-sts.domain1.example.  TXT "v=STSv1; id=2026072401;"
_mta-sts.domain2.example.  TXT "v=STSv1; id=2026072401;"
# 两个域名共用同一策略 JSON
# https://mta-sts-policy.example.com/.well-known/mta-sts.txt
{
  "version":"STSv1",
  "mode":"enforce",
  "mx": ["mx1.central.example", "mx2.central.example"],
  "max_age": 86400
}

注意:此模式要求所有共享域名的 MX 服务器完全一致,且 TLS 证书的 SAN 列表必须覆盖所有共享域名。

3.3 通配符策略模型

对于拥有大量子域名的组织(如 *.sub.example.com),RFC 8461 未定义 DNS 通配符发现机制。每个子域名仍需独立的 _mta-sts TXT 记录。但 HTTPS 策略文件可以通配管理:

典型部署方案:为所有 *.sub.example.com 配置一条通配 DNS A/AAAA 记录 *.mta-sts.sub.example.com,使每个 _mta-sts.*.sub.example.com 都自动解析到同一台 HTTPS 服务器。之后策略文件根据请求的 Host 头动态生成对应的 JSON 内容。

4. Wildcard MX 兼容性分析

Wildcard MX 记录(如 MX *.mail.example.com)在 DNS 层面是有效的——任何不存在的 X.mail.example.com 会匹配通配记录。但 MTA-STS 策略中的 mx: 字段要求精确匹配实际连接的 MX 主机名。RFC 8461 §3.2 规定策略中列出的 mx 值必须与 DNS MX 查询返回的主机名完全一致[1]。

这意味着:

# DNS Zone
*.mail.example.com. 300 IN MX 10 mail1.example.com.
*.mail.example.com. 300 IN MX 20 mail2.example.com.

# 假设实际查询返回的 MX 主机名为 mail1.example.com / mail2.example.com ——
# 策略中必须使用实际名称,不可写星号
# 正确:
{"version":"STSv1","mode":"enforce","mx":["mail1.example.com","mail2.example.com"],"max_age":86400}
# 错误:
{"version":"STSv1","mode":"enforce","mx":"*.mail.example.com","max_age":86400}

风险场景:接收方在 DNS 中动态增删 MX 主机名(如自动扩展场景),而 MTA-STS 策略无法自动感知——策略中的 mx 列表必须人工同步更新。若新增 MX 主机后未更新策略,发送方 MTA 会因主机名不在策略 mx 列表中而拒绝连接(enforce 模式下),导致邮件投递失败。

缓解措施

  1. 将 MX 主机名固定化,避免动态生成
  2. 使用较短的 max_age(如 86400 而非 604800)以减小策略滞后窗
  3. 先部署 testing 模式,确认 mx 列表枚举完整后再切换 enforce
  4. 配合 TLS-RPT 监控 "mx-mismatch" 类型的报告事件

5. TLS-RPT 多域报告聚合

TLS-RPT (RFC 8460) 定义了发送方 MTA 在 TLS 连接失败时,向接收方指定的报告地址 (_smtp._tls.example.com TXT 记录的 rua 字段) 发送 JSON 格式的失败报告[2]。报告中包含失败类型(如 certificate-expired、certificate-host-mismatch、starttls-not-supported)以及发送方信息。

5.1 多域名报告解析挑战

当一家企业运营 100 个域名时,每个域名都会产生 TLS-RPT 报告。Sending MTA 将报告投递到各自域名的 rua 邮箱中。运维人员面对的是来自 100 个不同收件箱的 JSON 报告流,难以聚合分析。

最佳实践:为所有子域名/品牌域名设置相同的 rua 地址,将报告集中到统一邮箱。再由报告解析器(如 python-tlsrpt 或自制解析服务)区分 report-policy-domain 字段——该字段顶部标识了报告所针对的接收方域名。

# TLS-RPT 报告 JSON 示例(节选)
{
  "organization-name": "ReceivingCorp",
  "date-range": {
    "start-datetime": "2026-07-23T00:00:00Z",
    "end-datetime": "2026-07-23T23:59:59Z"
  },
  "contact-info": "postmaster@receivingcorp.com",
  "report-id": "2026-07-23T00:00:00Z_receivingcorp",
  "policies": [{
    "policy": {
      "policy-type": "tlsa",
      "policy-string": ["_mta-sts.receivingcorp.com"],
      "policy-domain": "mail.receivingcorp.com",  ← 标识被报告域名
      "mx-host": "mx1.receivingcorp.com",
      "mx-service": "smtp",
      "mx-port": 25
    },
    "summary": {
      "total-successful-session-count": 4321,
      "total-failure-session-count": 7
    }
  }]
}

5.2 报告聚合脚本参考

#!/usr/bin/env python3
# tlsrpt_aggregator.py — 多域名 TLS-RPT 报告聚合
import json, sys, glob
from collections import defaultdict

failures_by_domain = defaultdict(lambda: defaultdict(int))

for report_file in glob.glob("/var/mail/tlsrpt/*.json"):
    with open(report_file) as f:
        report = json.load(f)
    for pol in report.get("policies", []):
        domain = (pol.get("policy", {})
                    .get("policy-domain", "unknown"))
        summary = pol.get("summary", {})
        for result_type in summary:
            if "failure" in result_type and summary[result_type] > 0:
                failures_by_domain[domain][result_type] += summary[result_type]

for domain, fails in sorted(failures_by_domain.items()):
    total = sum(fails.values())
    if total > 0:
        print(f"[ALERT] {domain}: {total} failures — {dict(fails)}")

5.3 告警阈值策略

并非所有 TLS-RPT 失败都需要触发告警。建议以下分级阈值:

级别阈值行为
INFO失败率 < 0.1%仅日志记录
WARN失败率 0.1%~1%邮件通知运维组
CRIT失败率 > 1% 或单个失败类型占比 > 0.5%即时告警+工单自动创建

certificate-expired 类型失败应始终触发 CRIT 级告警——这是证书运维失误的信号。

6. max_age 编排策略

max_age 决定了发送方 MTA 缓存策略的时长,直接影响多域名的策略更新速度:

推荐编排:日常使用 86400(1 天);在计划性 MX 变更前一周缩短至 3600;变更完成后逐渐恢复。这可以通过自动化脚本来实现:

#!/bin/bash
# deploy_mtasts_change.sh — MX 变更前的 max_age 递减策略
# 步骤 1: 将 max_age 降为 3600(提前 48h 执行)
curl -X PUT -d '{"version":"STSv1","mode":"enforce","mx":["mx1.old.example", "mx2.new.example"],"max_age":3600}' \
  https://mta-sts.example.com/.well-known/mta-sts.txt
# 增加 DNS 的 id 字段
./dns_update_txt.sh id=$(date +%s)

# 步骤 2: 等待 2 天(确保大部分发送方已缓存新策略)
sleep 172800

# 步骤 3: 实际变更 MX 记录
./dns_update_mx.sh

# 步骤 4: 确认无误后恢复 max_age
curl -X PUT -d '{"version":"STSv1","mode":"enforce","mx":["mx1.new.example", "mx2.new.example"],"max_age":86400}' \
  https://mta-sts.example.com/.well-known/mta-sts.txt
./dns_update_txt.sh id=$(date +%s)

7. 常见配置陷阱

7.1 证书 SAN 遗漏

多域共享 MX 时,MX 服务器的 TLS 证书 SAN 必须包含所有域名。RFC 6125 §6.4.4 规定 SMTP 的证书验证使用 dNSName 匹配接收方 MX 主机名[3]。如果某个域名的 MX 主机名不在 SAN 中,发送方 MTA 会回退到 STARTTLS 的 opportunistic 模式,生成本地策略违规的 TLS-RPT 报告。

7.2 DNS 与 HTTPS 不一致

域名 A 的 DNS TXT 声明 id=2026072401,但 HTTPS 策略文件的 id 仍为 2026072300。发送方根据 DNS 的 id 判断策略已更新,但实际获取的仍是旧版策略。务必保持 id 同步。

7.3 中间件超时

发送方在 TLS 握手阶段如果被接收方前端的反垃圾网关、负载均衡器等中间件中断(如 timeout 过短),会被归类为 starttls-not-supported 或 connection-timed-out。检查 TLS-RPT 中的 mx-host 字段,排除中间件干扰。

8. MTA-STS 与 DANE TLSA 的优选

RFC 8461 §7 指出,当接收方同时发布了 MTA-STS 和 DANE TLSA (RFC 7672) 时,发送方应优先使用 DANE,因为 DANE 基于 DNSSEC 提供了更强的信任锚点[4]。在多域名场景中,同时部署 MTA-STS 和 DANE 的企业需要确保策略不冲突:MTA-STS 的 mx 列表应包含所有 DANE TLSA 对应的 MX 主机名。

9. 总结

多域名 MTA-STS 部署的核心原则:故障隔离优先、策略共享降维、TLS-RPT 统一聚合。Wildcard MX 场景下需在策略中枚举所有实际主机名,无法使用通配符。max_age 的编排是 MX 变更窗口期的关键控制变量。建议所有多域名运营者每周至少检查一次 TLS-RPT 报告中的 policy-domain 分布,及时发现孤立域名的策略缺失。

参考文献

  1. RFC 8461 — SMTP MTA Strict Transport Security (MTA-STS). IETF, September 2018. Section 3 (MTA-STS Policy Records), Section 3.2 (mx: Field Definition), Section 7 (Relation to DANE).
  2. RFC 8460 — SMTP TLS Reporting. IETF, September 2018. Section 3 (TLS-Report DNS Record), Section 4 (Report Format), Section 4.3 (Result Type Enumeration).
  3. RFC 6125 — Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509. IETF, March 2011. Section 6.4.4 (SMTP Certificate Identity Check).
  4. RFC 7672 — SMTP Security via Opportunistic DANE TLS. IETF, October 2015. Section 3 (TLSA Records for SMTP).
  5. RFC 3207 — SMTP Service Extension for Secure SMTP over TLS. IETF, February 2002. Section 4 (STARTTLS).