Postfix TLS 部署:证书、目的地策略与握手核验
给 Postfix 打开 TLS,能保护一段 SMTP 连接上的邮件内容和认证交换,但连接“有加密”并不自动意味着“对端身份经过验证”。接收公网邮件、向互联网投递邮件、通过专用中继提交邮件,各自有不同的兼容性与信任边界。部署前先明确保护哪一段连接,再选择证书、信任根和目的地策略。
本文按用户指定边界整理 Postfix 官方 Postfix TLS Support:覆盖常规 RSA/ECDSA、入站与出站策略、SNI、CA/信任锚、证书深度、DANE、历史快速开始、私有 CA 工作流和源码编译,不纳入原页关于 ML-DSA 等新算法的实验。核对日期为 2026-10-05。版本要求按参数分别标注:smtpd_tls_chain_files 与服务器 SNI 映射从 Postfix 3.4 起提供;目的地 tafile/信任锚从 2.11 起提供;协议比较语法如 >=TLSv1.2 从 3.6 起提供;postfix tls 快速开始命令从 3.1 起提供。文中更早版本与参数默认值是历史兼容信息,不代表仍受支持;应以发行版维护的 Postfix/OpenSSL 手册为准。所有配置、安装、建表、清理、重载和探测命令均只经静态审阅,本次未执行。

先分清 smtpd_ 与 smtp_
smtpd(8) 是本机接收连接的 SMTP 服务端,对应 smtpd_tls_*;smtp(8) 是本机向下一跳投递的客户端,对应 smtp_tls_*。它们不是同一个开关。tlsmgr(8) 管理 TLS 相关随机状态和会话缓存,tlsproxy(8)、postscreen 等也参与某些连接路径。
例如,收信服务能展示证书,不代表本机投递时已验证远端证书;出站设为强制 TLS,也不会替本机的收信端安装证书。SMTP TLS 保护的是逐跳链路,不能据此保证邮件中转后的存储保密,更不能等同于端到端加密。
服务端证书文件:顺序、权限与轮换
服务端通常需要 PEM 格式的私钥和证书。Postfix 必须能在无人输入密码的情况下读取私钥,因此私钥不能依赖交互式解密口令;相应地,存放私钥的文件应由 root 持有并禁止其他用户读取。若证书与私钥合在一起,整个文件都按私钥保护;只有单独的公开证书文件可以公开读取。私钥不能贴进工单、日志或版本库。
Postfix 3.4 起推荐 smtpd_tls_chain_files。每组文件内容依次是私钥、与该私钥对应的服务器证书、签发它的中间 CA 证书,从叶子向上排列。普通公有 CA 校验通常不必发送根证书,因为受信任根应已在客户端;若采用以根 CA 为信任锚的特定 DANE TLSA 记录,则可能必须包含相应根证书,不能一概删掉。
# main.cf 中的 TLS 片段;不是完整邮件服务配置
smtpd_tls_chain_files = /etc/postfix/tls/rsa-chain.pem
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
只有已经准备好对应链文件时,才增加第二个 ECDSA 文件。原文允许多种算法共存,协商决定使用哪一组。本篇不照搬 DSA 或新算法的试验配置。若公布 DANE TLSA,所有实际提供的证书链都必须有相应匹配关系。
用一个包含密钥和证书的链文件,可以减少轮换时两个独立文件无法同时更新造成的错配窗口。仍须在受控暂存位置检查密钥与证书一致、链顺序及权限,再按站点流程原子替换;不要直接用重定向覆盖正在服务的链文件。旧的 smtpd_tls_cert_file、smtpd_tls_key_file 及算法专用参数属于旧接口,迁移时应明确清理或留空相关旧配置,避免混用后难以判断哪个配置生效。
“没有公有 CA 签名”也不意味着可以不给公网 MX 配证书。自签名或私有 CA 证书仍可用于机会式加密,但不应被描述为已通过公众信任链验证。原文明确不推荐无证书模式;它破坏 TLS 1.3 兼容性,也会令许多 SMTP 客户端无法连接。
常规 SNI:按客户端请求的主机名选择服务端证书
Postfix 3.4 及以上的 SMTP 服务端可以用 tls_server_sni_maps,根据客户端在 TLS 握手中发送的 SNI 名称动态选择私钥和证书链。SNI 只决定服务端在同一个地址上返回哪张证书;它不替代证书名称验证、SMTP 的 HELO/EHLO、DNS 或收信授权,也不改变已建立 TLS 的加密等级。
# main.cf 示例:按本机支持的 map 类型选择数据库
tls_server_sni_maps = hash:/etc/postfix/tls_server_sni_maps
映射表以客户端提交的 DNS 名称为键,值指向该名称应使用的 PEM 私钥和证书链资料。私钥与映射数据库要按密钥同等保护;原文的测试步骤明确先设置 umask 077,避免测试表对其他用户可读。若数据库保存文件内容,应按该参数手册使用带 -F 的 postmap;不同映射类型、格式与版本应先核对本机手册,不要把普通查表数据库的生成命令直接套用。
常规验收时,客户端可用 OpenSSL 的 -servername 发送目标 SNI 名称,并检查服务端返回的证书 SAN、签发链和有效期。原页还给出隔离式 RSA 2048 测试流程:生成带 DNS SAN、CA:false 和 serverAuth 扩展的自签名链文件,比较私钥与证书公钥摘要,将名称映射到链文件并用 postmap -F 建表;之后在回环地址的未用端口加入临时 smtpd 服务、通过 postconf -M 与 tls_server_sni_maps 连接该表,重载后从本机用带 SNI 的 SMTP STARTTLS 握手检查结果,再用 postconf -MX 清除临时服务。
这组本地流程会创建私钥、写入映射数据库、增加/删除 master 服务并重载邮件服务,不是只读命令;只适合隔离的临时 Postfix 实例。本文没有照搬其自动挑选端口和重载脚本,也未运行该测试。ML-DSA 等新算法 SNI 测试按既定范围排除。
公网 MX 和专用提交服务不能用同一套强制策略
smtpd_tls_security_level=may 让服务端公布 STARTTLS,但允许不使用 TLS 的发送方投递。公网 MX 不应直接改成 encrypt,否则不具备相应能力的发送方无法交付邮件。专用 MSA 或组织内中继可以按明确约定强制 TLS,但应在专用服务上配置,并保留原有认证与中继限制。
启用 SASL AUTH 的服务还要关注 smtpd_tls_auth_only=yes:它限制 AUTH 只在 TLS 激活后提供。原文为兼容性展示的默认值是 no,不能把这个默认示例误当成保护密码的推荐设置。该参数不会自动配置 SASL,也不会建立防开放中继规则。
465 端口常用的 wrapper 模式从连接开始就使用 TLS,不是先 SMTP 再 STARTTLS。原文要求在 master.cf 的专用服务通过 -o smtpd_tls_wrappermode=yes 启用,不建议全局放在 main.cf。这与 25/587 上的 STARTTLS 是不同握手路径,核验时必须选对方式。
Postfix 当前常把 465 端口服务称为 submissions(旧称 smtps);587 通常是先建立 SMTP 会话、再发起 STARTTLS。两者服务定义与客户端连接命令不同,不能只根据端口号假定握手模式。
如果专用服务要求 TLS 1.2 及以上,Postfix 3.6 起可使用 smtpd_tls_mandatory_protocols=>=TLSv1.2;旧版本使用排除列表的写法不同。机会式 TLS 对应 smtpd_tls_protocols,强制 TLS 对应 smtpd_tls_mandatory_protocols,不要把它们混淆。原文中的 SSLv2、SSLv3、TLSv1 历史例子是兼容性说明,不应据此重新开放过时协议。套件级别还取决于实际 OpenSSL,不能仅凭 high 字样就宣称所有安全要求已满足。
向远端 465 submissions 服务投递
Postfix 3.0 起,SMTP 客户端内置 465 submissions(旧称 smtps)服务支持。连接从一开始就使用 TLS;客户端必须把安全级别设为 encrypt 或更高。下面是把全部远端邮件交给一个明确配置的服务商的示例,会改变邮件路由,不能直接用于生产:
# main.cf:Postfix 3.0 及以上,部署前确认服务商、认证与证书策略
smtp_tls_security_level = encrypt
smtp_tls_wrappermode = yes
relayhost = [mail.example.com]:submissions
若只把某一域的邮件送往 465,可用 transport map 指向专用 SMTP 服务;生成 map 并重载会改变投递行为,本稿未执行:
# /etc/postfix/transport 示例
example.com relay-submissions:example.com:submissions
# main.cf 与 master.cf 片段;须与既有传输规则合并
transport_maps = hash:/etc/postfix/transport
# master.cf
relay-submissions unix - - n - - smtp
-o smtp_tls_security_level=encrypt
-o smtp_tls_wrappermode=yes
远端 465 wrapper TLS 与 587 STARTTLS 是不同的连接模式;选错会导致握手失败。常见的服务端 465 listener 名称为 submissions,不能与本机作为客户端连接远端服务的参数混为一谈。
客户端证书和“信任远端证书”不是一回事
出站客户端通常不需要自己的 TLS 证书。仅当远端明确要求客户端证书认证时,才配置 smtp_tls_chain_files 等参数。另一方面,验证远端服务端证书时,需要通过 smtp_tls_CAfile 或 smtp_tls_CApath 指定可信 CA。前者是 PEM 集合,后者是带正确哈希索引的证书目录。
原文指出 CAfile 在进入可选 chroot 前读取,而 CApath 的证书会按需读取,因而 CApath 必须能从 chroot 内访问。盲目复制宿主机路径可能表现为“证书存在但进程找不到”。这些信任设置也不应被当作“随便添加任何 CA 都可以”的修复办法。
Postfix 2.11 起,smtp_tls_trust_anchor_file 与目的地策略中的 tafile 可进一步限制信任链:设置后,CAfile/CApath 中的根 CA 不再生效,客户端只信任这些锚点文件所列锚点签发的链。锚点可为中间 CA 或公钥,且锚点本身不检查有效期;锚点以上未信任的父证书会被忽略。因此,tafile 不是通用“追加 CA”选项,采用前要确认锚点边界、目标匹配名和完整回退策略。策略表允许为一个目的地列出多个 tafile 属性。
# main.cf:全局使用专用信任锚时
smtp_tls_trust_anchor_file = /etc/postfix/trust/partner-anchor.pem
# tls_policy 表中的单目的地示意值;需与实际下一跳键对应
[relay.example.org]:587 secure tafile=/etc/postfix/trust/partner-anchor.pem
接收端默认不请求客户端证书。smtpd_tls_ask_ccert=yes 会改变握手;强制客户端证书的 smtpd_tls_req_ccert=yes 只有在强制 TLS 时才生效。除非确实用它做访问控制,否则请求客户端证书会增加开销并可能引入互操作问题。
尤其不要把 permit_tls_all_clientcerts 与面向公众的大型信任根集合随意组合。它会授权通过受信 CA 校验的客户端,可能把范围扩大到所有持有该 CA 有效证书的人。原文更倾向于显式列出允许的证书或公钥指纹,并保留 reject_unauth_destination 等中继保护。这是认证与授权的交界,必须审查完整规则顺序,不能只复制一条 permit。
客户端证书的精确授权表
客户端证书请求只有在确实用于访问控制时才有必要。permit_tls_clientcerts 只允许其证书指纹(或 Postfix 2.9 及以上支持的公钥指纹)出现在 relay_clientcerts 表中的客户端;check_ccert_access type:table 则用客户端证书/公钥指纹查询指定的 access(5) 表。为便于轮换和撤销,优先逐个列出授权证书或公钥,不要把所有由宽泛 CA 签发的证书都视为获准中继。
# main.cf 片段:客户端证书访问控制;合并时保留现有SASL/客户端规则
smtpd_tls_ask_ccert = yes
relay_clientcerts = hash:/etc/postfix/relay_clientcerts
# Postfix 2.10 起;这是策略示例,不要覆盖其他既有授权项
smtpd_relay_restrictions =
permit_mynetworks
permit_sasl_authenticated
permit_tls_clientcerts
reject_unauth_destination
# /etc/postfix/relay_clientcerts:源文的历史 MD5 格式演示值
# 仅说明“指纹 标签”的表项结构;不要复制用于当前 SHA-256 配置
D7:04:2F:A7:0B:8C:A5:21:FA:31:77:E1:41:8A:EE:80 lutzpc.at.home
# 当前配置须使用按 smtpd_tls_fingerprint_digest 算出的匹配指纹
<SHA-256-fingerprint> partner-a
permit_tls_clientcerts 要求客户端证书指纹(或 Postfix 2.9 及以上支持的公钥指纹)出现在 relay_clientcerts 表中;check_ccert_access type:table 则使用指纹作为 access(5) 表的查询键,可按表项结果作访问决策。若采用后者,应把 check_ccert_access hash:/etc/postfix/clientcert_access 插入既有的 smtpd_client_restrictions 规则列表中的适当位置;它是一个规则片段,不是可覆盖整项现有设置的独立配置。
证书指纹摘要算法由 smtpd_tls_fingerprint_digest 控制。Postfix 3.6 且兼容级别为 3.6 或更高时,默认值为 SHA-256;较早版本可能默认 MD5,源文中的 16 字节指纹是历史示例,不会匹配采用 SHA-256 的现行配置。新配置应显式核对算法与表中指纹格式。证书认证负责识别持证者,授权表决定它能否中继;规则应合并到完整的现有策略中,并保留 reject_unauth_destination 等保护。绝不能仅凭一次 permit 删除开放中继保护。
出站安全等级:加密与认证分别回答什么问题
| 等级 | 行为 | 关键限制 |
|---|---|---|
none |
不使用 TLS。 | 明确允许明文,不是故障排查的通用解决办法。 |
may |
对方提供 STARTTLS 时尝试加密;没有支持或握手失败时可明文投递。 | 不要求证书可信或名称正确,不能防所有主动降级。 |
encrypt |
必须建立加密连接,否则该目的地投递延迟。 | 仍可接受不可信或名称不匹配的证书;强制加密不等于验证身份。 |
verify |
要求可信证书链和匹配名称。 | 默认名称来自远端主机名;若它取自不可信 MX 查询,仍有 DNS 伪造风险。 |
secure |
要求可信证书链,并按可信的下一跳或显式 match 规则核验名称。 | 适合有明确约定的目的地;将 hostname 重新加入匹配策略可能破坏对 DNS 伪造的抵抗。 |
fingerprint |
与预先安全交换的证书或公钥指纹匹配。 | 不走普通 CA 链、到期日期校验;指纹更新与轮换必须维护。 |
dane / dane-only |
依据 DNSSEC 验证过的 TLSA 记录决定认证。 | 有严格 DNSSEC 前提,二者的无记录回退行为不同。 |
证书链允许的 CA 层数由 smtp_tls_scert_verifydepth 控制。当前文档默认是 9,沿用 OpenSSL 默认值;在 Postfix 2.5 之前,该参数曾被忽略。深度设为 1 时,只能验证由已信任 CA 直接签发的服务端证书,所有需要的中间 CA 必须显式配置;设为 2 时,可验证根 CA 直接签发的证书,也可验证由根 CA 签发的直属中间 CA 再签发的服务器证书,但服务器须正确提供中间证书。深度并非越大越安全,也不是修补缺失中间证书或错误信任根的替代手段。
# main.cf 示例;先按实际证书链计算并验收
smtp_tls_scert_verifydepth = 2
普通互联网出站不宜一刀切为 encrypt、verify 或 secure,否则不满足条件的目的地邮件会留在队列。常见做法是默认机会式 TLS,对已有约定的目的地加强策略:
# main.cf:示意片段,CA 路径应按本机实际设置
smtp_tls_security_level = may
smtp_tls_loglevel = 1
smtp_tls_CAfile = /etc/postfix/CAfile.pem
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
以上 hash 是原文采用的查找表类型。发行版构建可能不支持它;应先用 postconf -m 查看支持类型,再使配置、生成表和查询命令保持一致。
目的地策略表的键必须与实际下一跳一致
TLS 策略表按完整下一跳检索,可能是收件域,也可能来自 transport、relayhost 或其他路由设置。方括号和端口是键的一部分;[mail.example.org]:587、[mail.example.org] 和不带括号的域不是可以随意替换的同一个键。证书名称校验则只使用相应域名,不包含方括号和端口。
# /etc/postfix/tls_policy
# 示例保留域名,必须按已约定的路由与证书名称替换
example.com secure match=example.com:.example.com
example.net encrypt protocols=>=TLSv1.2
[mail.example.org]:587 secure match=mail.example.org protocols=>=TLSv1.2
第一行要求证书适用于 example.com 或其子域;第二行只要求加密,不验证身份,适用于确实只约定了这种保证的目标;第三行体现带端口的中继下一跳。protocols=>=TLSv1.2 是 Postfix 3.6 起的语法。多条 match 或协议策略使用的分隔符要按该表语法处理,不要拿 shell 列表格式替代。
无括号、无端口的域名键查不到时,还会按带前导点的父域规则继续查找,因此 .example.com 规则会影响子域。新规则上线前应同时核验准确域名、子域和实际中继键,避免误伤与遗漏。
# 只读核对:当前支持的查找表类型
postconf -m
# 仅当配置确实使用 hash,且策略文本已审阅时生成数据库
postmap hash:/etc/postfix/tls_policy
# 只读查询生成后的表;此命令本身不证明投递路径选中了该键
postmap -q '[mail.example.org]:587' hash:/etc/postfix/tls_policy
postmap 的生成动作会写数据库文件;本篇没有执行。路由、表类型和权限都确认后,才按维护流程加载配置并观察邮件队列。这里没有提供会先批量清空现有 TLS 设置的快捷命令:原文快速开始部分的 postconf -X 例子确实会删除已有 TLS 参数,不能当作无损“开启 TLS”步骤。
DANE 的保证来自经过验证的 DNS 链
dane 与 dane-only 从 Postfix 2.11 起提供。对某台远端服务器,dane 得到可用且可信的 TLSA 记录时必须按记录认证;认证失败不会回退到未认证或明文投递。没有 TLSA 时,它的行为与 may 相同;存在 TLSA 但全部因参数等原因不可用时,行为相当于强制但未认证的 encrypt。dane-only 则在没有可用 TLSA 或认证失败时延迟投递。
TLSA 必须来自 DNSSEC 验证成功的区域。客户端需要支持相关能力的 OpenSSL 和编译期 DNS 库,smtp_dns_support_level=dnssec,smtp_host_lookup 包含 DNS,以及可信的 DNSSEC 验证递归解析器。Postfix 内部的 stub resolver 自己不做完整 DNSSEC 验证;原文强烈建议每台 MTA 使用本机回环接口上的验证解析器,避免到解析器的通道破坏信任假设。
使用 DANE 时,TLSA 记录的基域会被无条件用作 SNI 名称,服务器证书还必须匹配 TLSA 记录。它与常规按目的地配置的 SNI 映射是两条不同路径;要一并检查 TLSA 基域、MX 路由和证书关联类型。
这也解释了为什么不能只在 main.cf 添一行 smtp_tls_security_level=dane 就宣布 DANE 已完成。还要核验目的域、MX 主机区域、解析结果、TLSA 记录和所有候选 MX 的一致性。TLSA 不会取代正常 MX 选择;一组 MX 的部署不一致,可能导致不同投递路径得到不同保护。
Postfix 的 SMTP DANE 支持证书用途 2 和 3;用途 0、1 在这里被视为不可用。用途 3 的终端实体关联直接匹配证书或公钥,不使用普通 Web PKI 的名称与到期日期检查。原文建议的 3 1 1 是终端实体、公钥、SHA-256 的组合;它允许同一密钥续证时保持摘要不变。若更换密钥,应提前发布新旧摘要并让旧 DNS 缓存充分过期,再切换服务端,最后撤掉旧关联。轮换顺序错误可能导致投递延迟。
握手核验要同时看名称、信任与实际投递策略
先检查安装版本、非默认配置和证书链,再在获得授权的专用测试目标进行握手。下面是本文补充的 OpenSSL 检查示例,依据 官方 s_client 文档;它不是原文已测结果,也没有在本次运行。替换为测试主机和受信 CA 文件后,使用正确的 SMTP STARTTLS 路径:
openssl s_client -starttls smtp \
-connect mx.example.net:25 \
-servername mx.example.net \
-verify_hostname mx.example.net \
-verify_return_error \
-CAfile /etc/postfix/CAfile.pem \
-showcerts
-servername 提供 SNI,-verify_hostname 指定要验证的名称,两者作用不同。-verify_return_error 很重要:s_client 作为调试工具默认可能在证书校验出错后继续握手,单看“连上了”会造成误判。查看链、校验结果、协商协议和套件后,用 SMTP QUIT 结束连接;465 wrapper 服务不使用 -starttls smtp。
这项探测检验的是指定主机上的公有/私有 CA 信任路径,不等于复现 Postfix 的 MX 路由、策略表匹配或 DANE 验证。还须在隔离验收环境核对真实下一跳、最终使用的策略,以及不满足策略时确实延迟而非悄悄明文投递。本文不提供虚构的“验证成功”输出。
smtpd_tls_loglevel=1 与 smtp_tls_loglevel=1 可记录握手摘要。级别 2 增加协商信息,3 会转储握手,4 连 STARTTLS 后的传输数据也会转储;原文强烈不建议级别 4。日志可能包含敏感内容,排查时应最小化范围与保留时间。Received 头里的 TLS 信息也不应被当作全链路证据,因为中转节点可以改变邮件头。
LMTP 客户端沿用对应的 TLS 参数
Postfix 的 smtp(8) 与 lmtp(8) 投递代理共用客户端实现;远端 LMTP 的 TLS 参数与 SMTP 对应,通常把 smtp_ 前缀替换为 lmtp_。通过 Unix-domain socket 投递时,证书核验使用本机 $myhostname 作为下一跳名称。源文明确说明:对 Unix socket 上的 LMTP 配置机会式 may 会被忽略并在邮件日志中给出警告,因为本地 socket 本来就不提供 TLS 的机密性收益;若本地链路确需 TLS,应要求强制加密并核验身份,而不是把 may 当作安全保证。
缓存、默认值和变更记录
连接复用与 TLS 会话缓存是不同功能。Postfix 3.4 起,客户端可复用已建立的 TLS SMTP 连接进行多次投递;它默认关闭,可在确认远端兼容后设置 smtp_tls_connection_reuse=yes,也可在目的地策略表中使用 connection_reuse=yes。连接复用需要 scache 与 tlsproxy 协作,能否减少成本取决于实际对端节流与流量模式。
# main.cf:Postfix 3.4 及以上;需要先评估对端兼容性
smtp_tls_connection_reuse = yes
会话缓存复用的是 TLS 握手协商信息。客户端各 smtp 进程默认只在本进程存活期间缓存;要跨进程共享,可配置由 tlsmgr(8) 维护的持久缓存数据库。缓存应位于 Postfix 所有的 data_directory,数据库须支持 sequence 操作并容纳数 KB 对象;DBM 不适用。源文历史默认缓存期限为 3600 秒。Postfix 2.11 起,期限超过 100 天无效;设为 0 或负数会关闭缓存;正数小于两分钟时会采用两分钟下限。
smtp_tls_session_cache_database = btree:/var/lib/postfix/smtp_scache
smtp_tls_session_cache_timeout = 3600s
服务端 TLS 会话缓存通常可使用 TLS 会话票据而不保存外部数据库;原文指出 Postfix 2.11 起,在相应 OpenSSL/客户端支持下通常把 smtpd_tls_session_cache_database 留空。缓存目录与随机状态由 tlsmgr(8) 等组件维护,历史的 tls_random_source 设定和数据库类型必须按当前构建、数据目录与操作系统核实,不能照抄旧随机设备路径。
tlsmgr 随机状态、熵源与持久文件
tlsmgr(8) 不只维护 TLS 会话缓存,也维护供 smtp(8) 与 smtpd(8) 初始化时取种子的 PRNG 池。源文描述的默认请求量和每次从熵源读取量均为 32 字节;定期重播种最大间隔默认一小时,实际触发时间在 0 到这个上限之间随机选择。外部熵源必须是非阻塞来源;源文举例为 EGD 或 /dev/urandom,OpenBSD 在出现读取超时的特定情况下可用 /dev/arandom。非普通文件的源名需要用 dev: 或 egd: 指定类型。
tlsmgr 还会把 PRNG 状态写入持久 exchange 文件,以便进程重启后恢复。Postfix 2.5 起该文件应位于 Postfix 所有的 data_directory,并由 mail_owner 账户管理;不要把旧版本文件位置或 root 读写假设直接套到当前软件包。下面只列源文参数作为定位线索,安装前应核对本机手册和默认值:
# 历史参数示例:只在核实目标 Postfix 版本和目录后考虑
tls_daemon_random_bytes = 32
tls_random_source = dev:/dev/urandom
tls_random_bytes = 32
tls_random_reseed_period = 3600s
tls_random_exchange_name = /var/lib/postfix/prng_exch
tls_random_prng_update_period = 3600s
原文还保留了早期 OpenSSL、旧算法及兼容性参数的历史描述。不要复制“关闭所有 workaround”的十六进制掩码或旧协议配置去解决一般错误;这些参数与具体库版本耦合,应先定位失败原因。更改信任根、match、TLSA、协议下限和权限,都可能影响投递可用性,应保存改动前配置、预期目标及核验记录,并准备按已审阅的差异回退。
Postfix 3.1 起的快速开始命令会更改配置
原文称 Postfix 3.1 起提供 postfix tls 帮助命令。在客户端 TLS 参数仍处默认状态时,postfix tls enable-client 会启用机会式出站 TLS;服务端对应命令会启用机会式入站 TLS,并生成自签名私钥/证书。命令在已安装 Postfix 系统上修改配置,后续 postfix reload 会让运行中的服务重读配置;服务端命令不等于设置公有 CA、客户端证书或 DANE。
# 仅在确认当前实例、配置备份与目标后执行;本次未执行
postfix tls enable-client
postfix reload
postfix tls enable-server
postfix reload
若 TLS 设置已不是默认状态,原文说快速开始命令会拒绝覆盖并提示最小调整。原文另给出先清除全部 SMTP TLS 设置、再恢复 stock 配置的命令,但该动作会删除现有设置而不是只修复当前键,可能移除策略表、信任根、协议限制或密钥路径。这里保留命令以解释原文的操作含义,明确标成高风险示例;不要在生产系统粘贴。
原文的重置命令(会清除设置,不作为推荐操作)
# 有破坏性:先清除现有的全部匹配参数,再启用客户端 TLS
postconf -X `postconf -nH | grep -E '^smtp(_|_enforce_|_use_)tls'`
postfix tls enable-client
postfix reload
# 有破坏性:先清除现有的全部匹配参数,再启用服务端 TLS
postconf -X `postconf -nH | grep -E '^smtpd(_|_enforce_|_use_)tls'`
postfix tls enable-server
postfix reload
原文说明这些快速命令不能替代 DANE 部署:DANE 还要求修改解析配置、具备 DNSSEC 验证能力的本地递归解析器,以及符合 DNS 库、OpenSSL 与 Postfix 构建条件的环境。
自签名证书与私有 CA:保留历史流程,并标出过时项
自签名证书可用于让兼容的客户端机会式加密,但公共发件方通常不信任它;有验证需求的专用中继需另行把正确 CA 配入信任链。原文的手工自签名示例用 RSA 2048、有效期 3,650 天,并把 CN 作为名称。它是历史便利示例,不是现代公有 MX 推荐:有效期很长,且没有展示 SAN,不能假定现代客户端会仅凭 CN 完成主机名验证。命令还会在 Postfix 配置目录创建私钥、使用 rm -f 清理同名日期文件,并用 postconf -e 改写多个活动参数;目标路径错误或复用同一天文件名可能覆盖已有材料。
原文 2048 位、十年期自签名示例(仅供逐项审阅;不要原样执行)
# 高影响示例:创建私钥/证书并写入 main.cf;本文没有执行
dir="$(postconf -h config_directory)"
fqdn="$(postconf -h myhostname)"
case "$fqdn" in /*) fqdn="$(cat "$fqdn")";; esac
ymd="$(date +%Y-%m-%d)"
key="${dir}/key-${ymd}.pem"; rm -f "${key}"
cert="${dir}/cert-${ymd}.pem"; rm -f "${cert}"
(umask 077; openssl genrsa -out "${key}" 2048) && \
openssl req -new -key "${key}" \
-x509 -subj "/CN=${fqdn}" -days 3650 -out "${cert}" && \
postconf -e \
"smtpd_tls_cert_file = ${cert}" \
"smtpd_tls_key_file = ${key}" \
'smtpd_tls_security_level = may' \
'smtpd_tls_received_header = yes' \
'smtpd_tls_loglevel = 1' \
'smtp_tls_security_level = may' \
'smtp_tls_loglevel = 1' \
'smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache' \
'tls_random_source = dev:/dev/urandom'
原文还给出 OpenSSL 的私有 CA 工作流:用随 OpenSSL 安装的 CA.pl -newca 建 CA 私钥与公开 CA 证书(CA 私钥以口令保护);为邮件主机建立 CSR 和无人值守可用的主机私钥;由 CA 用 openssl ca 签发证书;最后将主机私钥、主机证书和 CA 证书分开安装。Postfix 的服务端私钥必须能在无交互提示时读取,所以主机密钥不加密时,文件权限尤其关键;CA 私钥则不应复制到邮件服务器上。
# 历史 CA.pl 示例骨架;必须先按当前 OpenSSL 配置和企业 PKI 策略审阅
# CA.pl 会在 demoCA/private/cakey.pem 保存 CA 私钥,demoCA/cacert.pem 保存公钥证书
/usr/local/ssl/misc/CA.pl -newca
# 为主机创建 CSR 和 Postfix 可读取的无口令私钥;-nodes 是敏感选择
(umask 077; openssl req -new -newkey rsa:2048 -nodes \
-keyout host-key.pem -out host-req.pem)
# 由 CA 签名;原文示例有效期为 365 天
openssl ca -out host-cert.pem -days 365 -infiles host-req.pem
# 示例目标路径;运行前须确认不会覆盖现有密钥或证书
cp demoCA/cacert.pem host-key.pem host-cert.pem /etc/postfix/
chmod 644 /etc/postfix/host-cert.pem /etc/postfix/cacert.pem
chmod 400 /etc/postfix/host-key.pem
静态安全核查:原页交互输出显示旧的 CA.pl 配置会生成仅 1,024 位 RSA CA 私钥;示例 CSR 只询问 DN/CN,没展示现代验证需要的 SAN 扩展;示例还有已过期于 2005 年的历史签发输出。当前 OpenSSL、CA 工具与证书验证规则可能拒绝或判定这些材料不安全,不能用原样命令建立新的生产 CA。应由适用的组织 PKI/现代 CA 流程发证,配置正确 SAN、密钥参数、期限、用途与链;本篇保留旧工作流便于理解,不把它包装为当前推荐。
原文配置同时展示 smtp_tls_CAfile(出站验证远端)、smtpd_tls_CAfile(服务端请求/验证客户端证书)、smtpd_tls_cert_file / smtpd_tls_key_file、机会式安全等级与日志参数。两种 CAfile 角色不同。示例还把旧会话缓存数据库和随机源参数放进配置;数据库类型、目录与随机源均应核对当前平台及 Postfix 默认,不应因旧示例出现就照抄。对新配置优先使用前文的 smtpd_tls_chain_files,不要混用新旧证书参数。
从源码编译 TLS:平台与链接器参数是构建条件
原文源码编译说明要求在 Postfix 顶层源码树运行 make makefiles,并定义 USE_TLS、OpenSSL 头文件位置和链接库。以下只用于解释原文的构建参数;make tidy 会清理已有构建产物,不能在不确认内容的工作树中运行。发行版源码包、OpenSSL 版本、系统链接器与其他附加功能可能要求不同组合。
# OpenSSL 头文件位于 /usr/include/openssl、库位于 /usr/lib 的示意
make tidy
make makefiles CCARGS="-DUSE_TLS" AUXLIBS="-lssl -lcrypto"
# 安装在 /usr/local 的示意
make tidy
make makefiles CCARGS="-DUSE_TLS -I/usr/local/include" \
AUXLIBS="-L/usr/local/lib -lssl -lcrypto"
# 运行时链接器不搜索该目录时,原文示例在 crypto 库后加入 rpath
make makefiles CCARGS="-DUSE_TLS -I/usr/local/include" \
AUXLIBS="-L/usr/local/lib -lssl -lcrypto -Wl,-R,/path/to/directory"
# 原文给出的 Solaris 变体
make makefiles CCARGS="-DUSE_TLS -I/usr/local/include" \
AUXLIBS="-R/usr/local/lib -L/usr/local/lib -lssl -lcrypto"
如果还需要 Berkeley DB、MySQL、PostgreSQL、LDAP 或 SASL 等功能,须把各自文档中的 -D/-I 编译参数与 -l/-L 链接参数合并,不要原样复制文字占位符。随后继续按 Postfix 的 INSTALL 指南完成其余构建与安装步骤。原 TLS 文档还留下“不要使用 GnuTLS,因为会导致 daemon 退出方式不合预期”的强烈警告;它属于版本和实现背景相关的历史说明,本稿保留其存在但不外推为所有当前发行版的结论,须以当前官方构建文档与供应商包为准。
构建与配置命令的审阅结果:上列 make tidy、make makefiles、cp、chmod、CA.pl、openssl ca、postconf -e、postconf -X、postconf -M/-MX、postmap -F 与 postfix reload 都会写文件、改配置、删除参数、签发凭据、改建索引或影响服务;本次逐项只做静态审查,未运行任何一个。命令示例没有真实秘密;真实私钥、CA 口令和服务凭据不应放进稿件、日志或版本库。
来源与归属
原文维护方为 Postfix Project。其 Credits 说明:TLS 支持最初由 Cottbus Technical University 的 Lutz Jänicke 开发;Wietse Venema 接纳、重构代码,并从 Lutz 的文档编纂这部分说明;Victor Duchovni 参与重做安全等级、实现指纹等级,并分离连接管理与策略执行。这里保留原页致谢中的姓名与角色,不把教程虚构为某一个人的署名文章。
本篇由未完纪整理,范围依据官方 Postfix TLS 文档。本稿补充常规 SNI/证书深度/信任锚、TLS 构建、快速开始与私有 CA 章节,并对原文中会重置配置、生成/安装密钥和重载服务的示例加上静态风险标注;范围不包括原文中标为实验性的新算法。中文译写与配图依据另行授权制作。Postfix 软件的 IBM Public License 1.0 / Eclipse Public License 2.0 双许可线索不被自动推定为本网页的独立许可;保留原页作者归属和来源链接。图示为原创整理。静态审阅所刊片段未发现硬编码秘密或不可信输入拼接;这不是对完整部署无漏洞的保证。











暂无评论内容