10 个版本
0.2.0-alpha.1 | 2024年6月13日 |
---|---|
0.1.0 | 2023年12月27日 |
0.0.7 | 2023年10月29日 |
0.0.5 | 2023年8月25日 |
0.0.1 | 2022年12月22日 |
84 在 电子邮件
74 每月下载量
300KB
7K SLoC
DKIM Milter
DKIM Milter 是一个使用 域名密钥识别邮件 (DKIM) 协议签名和验证电子邮件消息的 milter 应用程序。它旨在与具有 milter 功能的 MTA(邮件服务器)如 Postfix 集成。DKIM 由 RFC 6376 指定。
DKIM Milter 基于 viadkim 库。因此,它继承了该库中使用的 DKIM 方法。值得注意的是,viadkim 完全支持国际化电子邮件,包括在 d=
标签中的 Unicode 签名域(RFC 8616)。更实际的是,它继承了 viadkim 在处理大量或大型消息时的性能特征,并与异步范式 milter 实现相结合。
DKIM Milter 尽可能高效地工作。公钥查询是并行进行的。当多个签名使用相同的参数计算正文哈希时,哈希只计算一次,并将结果共享给所有签名。此外,当不需要计算正文哈希时,例如签名已经确定失败,将完全跳过正文处理。另一个例子是处理大型消息:DKIM Milter 以固定大小的块处理消息正文,这意味着即使同时处理数百个每条一两个兆字节的消息,它也不会受到压力;在任何时刻,这些消息正文的 总 内存使用量永远不会超过几兆字节左右(即,与消息数量相关,而不是其大小)。
DKIM Milter 可以作为 OpenDKIM milter 的简单替代品。归功于该项目,我已经长期使用该项目,并且该项目也启发了这里的一些选择。
安装
DKIM Milter 是一个 Rust 项目。它可以像往常一样使用 Cargo 构建/安装。例如,使用以下命令安装在 crates.io 上发布的最新版本
cargo install --locked dkim-milter
在构建和安装过程中,可以指定选项 --features pre-rfc8301
以将加密算法和密钥使用回滚到 RFC 8301 之前:它启用了对不安全的、历史性的 SHA-1 算法的支持,并允许使用低于 1024 位的长度的 RSA 密钥。不建议使用此功能。
以下各节将讨论,默认的编译内配置文件路径为 /etc/dkim-milter/dkim-milter.conf
。在构建DKIM Milter时,可以通过设置环境变量 DKIM_MILTER_CONFIG_FILE
为期望的路径来覆盖此默认路径。
最低支持的Rust版本是1.74.0。
用法
安装后,DKIM Milter可以通过命令行作为 dkim-milter
启动。
配置参数可以在默认配置文件 /etc/dkim-milter/dkim-milter.conf
中设置。必须在该文件中设置强制参数 socket
。
调用 dkim-milter
将在前台启动milter。向进程发送终止信号或按Control-C以关闭milter。在milter运行时,发送SIGHUP信号以重新加载配置。
DKIM Milter通常作为系统服务设置。使用提供的systemd服务作为起点。请参阅包含的教程文档,了解如何创建系统服务。
支持的签名算法,包括签名和验证,是 rsa-sha256
和 ed25519-sha256
。默认情况下,不支持的旧签名算法 rsa-sha1
,此类签名的评估结果为 permerror(RFC 8301;但请参阅上面的功能 pre-rfc8301
)。
配置
默认配置文件是 /etc/dkim-milter/dkim-milter.conf
。包含的man页 dkim-milter.conf(5) 作为参考文档。(您可以通过将文件路径传递给 man
来在不安装的情况下查看man页: man ./dkim-milter.conf.5
)
请参阅包含的 示例配置,了解一组配置文件可能的样子。
有关DKIM Milter入门的动手实践介绍,请参阅包含的 教程文档。
设计
DKIM Milter配置由主要配置文件 dkim-milter.conf
以及提供额外表格配置的辅助文件或数据源组成。
主要配置文件包含全局设置。对于签名,配置从指定的数据源读取。
可以通过进一步数据源中指定的 overrides 覆盖全局设置以针对所选输入。覆盖可以应用于连接的网络地址、接收者(在 RCPT TO:
SMTP命令)和发送者(在 Sender 或 From 标题)。
例如,可以使用 recipient_overrides
参数指定某些消息接收者的配置覆盖。这允许全局禁用生成的签名中 l= 标签的使用,但仅对某些接收者启用。
这种设计,主要配置的参数可以通过一定的粒度进行覆盖,应该足够灵活,以满足许多配置需求。
签名-验证决策
对于传递给DKIM Milter的所有消息,消息是否应进行验证或签名的决策如下。
如果消息来自一个 可信源 并由匹配配置的 签名发送者 提交,则该消息将被签名。如果消息来自不受信任的源,则将其验证。换句话说,来自可信源的消息是授权的或符合签名的资格;它不符合验证的资格。
可信源是指来自 trusted_networks
(默认:回环地址)中的IP地址的连接,或者如果设置了 trust_authenticated_senders
(默认:是),则是经过身份验证的发送者。
消息的 发起者 来自消息的 Sender 头(如果存在),否则来自消息的 From 头。(通常,Sender 不存在,因此发起者将来自 From;然而,如果 From 包含多个邮箱,则必须根据RFC 5322包含 Sender,因此发起者将来自 Sender。)
签名发送者 是为它们设置了签名密钥和签名配置的发送者(域名或电子邮件地址)。它们在参数 signing_senders
指定的数据源中进行配置。
操作模式(仅签名、仅验证或根据上述程序自动进行)也可以通过 mode
参数进行配置。
签名发送者
签名配置通过两个指向表格文件(或其他数据源,见下一节)的配置参数进行设置。这些参数是 signing_senders
和 signing_keys
signing_senders = </path/to/signing_senders_file
signing_keys = </path/to/signing_keys_file
配置签名的关键是 签名发送者 表(参数 signing_senders
)。此表将发送者电子邮件地址链接到具体的签名配置
# Sender expression Domain Selector Signing key name
example.org example.org sel1 key1
.example.org example.org sel2 key2
发送者表达式 example.org
匹配该域名的发送者(me@example.org
)。发送者表达式 .example.org
匹配该域名的发送者和子域名(me@subdomain.example.org
)。注意:每个匹配的发送者表达式都会为消息生成额外的DKIM签名。在上面的例子中,来自 me@example.org
的消息使用两个密钥进行签名,因为两个发送者表达式都匹配该地址。(多重签名主要用于使用Ed25519和RSA密钥的双重签名。)
在 签名发送者 表的第四列中命名的密钥列在 签名密钥 表(参数 signing_keys
)中列出
# Key name Key source
key1 </path/to/signing_key1_pem_file
key2 </path/to/signing_key2_pem_file
密钥源必须是文件系统数据源(即,以 <
或 file:
前缀的路径)指向一个PKCS#8 PEM文件。签名密钥类型(RSA或Ed25519)会自动检测。
可以在可选的第五列中指定额外的每个签名(即,每个发送者表达式匹配)配置覆盖,在 signing_senders
文件中。
本节余下的部分简要介绍了某些附加功能。在域名列中,单个点 .
会复制匹配的发送者地址的域名。下面列表中的两个条目是等效的,两者都生成标签 d=example.com
# Sender expression Domain ...
example.com example.com ...
example.com . ...
签名发送者表也是配置 签名标识符 的地方,即生成的签名中的 i= 标签:默认情况下,签名不包括签名标识符;在域名列中使用 @
字符可以启用签名标识符。
# Sender expression Domain/Identity ...
example.com @example.com ...
example.com @. ...
# both => d=example.com, i=@example.com
# Double dot separates i= subdomain from d= domain.
mail.example.com @mail..example.com
# => d=example.com, i=@mail.example.com
# The local-part before the @ may be included literally.
example.com user@example.com
# => d=example.com, i=user@example.com
# A dot before the @ copies the sender’s local-part into the i= tag.
example.com .@example.com
# => d=example.com, i=user@example.com
数据源
上面介绍了几种类似表格的文件。事实上,这些都是 数据源 的更一般概念的一部分。某些配置参数引用表格数据 - 一系列条目 - 这些将由特定的数据存储提供。
目前有三个数据源可用:<
或 slurp:
,一次性从文件系统中读取数据并保存在内存中;file:
,每次需要时从文件系统中重新读取数据;(如果启用)sqlite:
,从 SQLite 数据库中读取数据。
内存文件系统数据源 以 <
或 slurp:
前缀的文件路径表示。
示例
signing_keys = </path/to/signing-keys
当使用此数据源时,数据会在启动时被积极读取和验证,并在内存中保持不变,直到终止(或重新加载)。查找是在内存中进行的,操作期间不会访问文件系统。
实时文件系统数据源 以 file:
前缀的文件路径表示。
示例
signing_keys = file:/path/to/signing-keys
使用此数据源时,数据仅在需要时读取,并不保存在内存中。文件更改将立即生效,无需重新加载或重启。
文件系统数据源有哪些用途?您可以仅使用 <
。整个配置将在启动时被积极读取,然后仅存在于内存中。如果您在所有地方都使用 file:
,则配置将在需要时读取,即文件系统被视为数据库,更改将自动并立即应用。另一种选择是,在整个过程中使用 <
,但使用 file:
为签名密钥文件本身:然后所有配置都保存在内存中,但(敏感的)密钥材料仅在签名时临时读取到内存中,使用后丢弃。
SQLite 数据源 以 sqlite:
前缀的 SQLite 数据库 URI 表示。此数据源仅在构建/安装时通过选项 --features sqlite
可用。如果需要,可以通过附加 #
后跟表名来自定义表名。
示例
signing_keys = sqlite://mail-config.db#dkim_signing_keys
数据库模式在其他地方有文档说明。
将来,可以添加更多数据源(SQL、LDAP、…)。
密钥设置
严格来说,密钥管理不在 DKIM Milter 的范围内。然而,有一个配套工具 dkimdo,您可以使用它手动进行密钥设置。以下是一个简要介绍。
对于签名,DKIM Milter 从 PKCS#8 PEM 格式的文件中读取 签名密钥(私钥)。这种格式可以通过其起始行 -----BEGIN PRIVATE KEY-----
来识别。
使用以下命令分别生成 RSA 2048 位或 Ed25519 私钥文件 private.pem
dkimdo genkey --out-file private.pem rsa
dkimdo genkey --out-file private.pem ed25519
这些命令为 RSA 或 Ed25519 密钥类型创建签名密钥文件。每个命令还会将相应的 DKIM 公钥记录 输出到标准错误流。例如,对于 RSA,打印的记录看起来像以下这样
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCA...
每个签名密钥的公钥记录必须作为TXT记录在DNS中公布,域名格式为:<选择器>._domainkey.<域名>
。具体操作方式取决于DNS软件和/或DNS服务提供商。
以下是一个示例,展示了如何使用dig
工具在DNS中查找以这种方式生成的公钥记录。注意选择器ed25519.2022
和域名gluet.ch
dig +short ed25519.2022._domainkey.gluet.ch txt
"v=DKIM1; k=ed25519; p=7mOZGVMZF55bgonwHLfOzwlU+UAat5//VJEugD3fyz0="
(上述Ed25519公钥记录可以放在单个文本字符串中。较大的RSA记录通常分散在几个文本字符串中。此类大型TXT记录的设置取决于DNS软件和/或DNS服务提供商。)
还可以使用dkimdo query
查询公钥记录。还可以使用dkimdo keyinfo
从现有的签名密钥生成公钥记录。
请注意,dkimdo的输出并非定制或神奇,您也可以使用OpenSSL项目的标准openssl
工具生成密钥材料。
许可证
版权所有 © 2022–2024 David Bürgin
本程序是自由软件:您可以在自由软件基金会发布的GNU通用公共许可证条款下重新分发和/或修改它,许可证版本为3,或(根据您的选择)许可证的任何较新版本。
本程序是在希望它将是有用的希望下分发的,但没有任何保证;甚至没有关于其商业性或针对特定目的的适用性的暗示保证。有关详细信息,请参阅GNU通用公共许可证。
您应该已经收到了GNU通用公共许可证副本。如果没有,请参阅https://www.gnu.org/licenses/。
依赖项
~15–32MB
~542K SLoC