跳转到内容
Integration

使用 GitHub Actions 在每次推送时审核域的电子邮件安全性

| 7 min read

一个 GitHub 操作,使用 botoi API 检查 SPF、DMARC 和 DKIM 记录,如果任何记录丢失或配置错误,则构建失败。

GitHub Actions workflow running in a terminal
Photo by Roman Synkevych on Unsplash

您团队中的某人更新了 DNS 记录。 TXT 条目在提供商迁移期间被删除。 您的 SPF 记录悄悄超出了 10 次查找限制。 电子邮件开始成为垃圾邮件。 没有人 通知两周,直到客户提到他们从未收到您的发票。

基于 DNS 的电子邮件安全记录(SPF、DMARC、DKIM)是一种基础设施, 完美地工作,直到它不起作用。 当它损坏时,故障模式是静默的:没有错误, 没有警报,电子邮件消失到垃圾邮件文件夹中。

本指南设置了一个 GitHub Action,用于验证每次推送时的所有三个记录。 如果 任何记录丢失或配置错误,工作流程都会失败并告诉您发生了什么问题。

工作流程的作用

每次推动 main,动作:

  1. 呼叫 botoi /v1/dns-security/spf-check 用于验证您的 SPF 记录的端点
  2. 通话 /v1/dns-security/dmarc-check 验证您的 DMARC 策略
  3. 通话 /v1/dns-security/dkim-check 验证您的 DKIM 密钥是否已发布
  4. 如果任何检查失败,则以非零代码退出,从而阻止合并

GitHub Action 工作流程

创造 .github/workflows/dns-security.yml 在你的存储库中:

代替 yourdomain.com 与您的域名和 google 与 您的电子邮件提供商的 DKIM 选择器。 工作流程在每次推送时运行 main, 按每日计划进行,并且可以从“操作”选项卡手动触发。

每项检查验证什么

SPF(发件人策略框架)

SPF 声明哪些邮件服务器有权为您的域发送电子邮件。 应用程序编程接口 返回原始记录、已解析的机制列表以及记录是否有效。

需要关注的关键领域:

  • has_spf: 是否有以以下开头的TXT记录 v=spf1? 如果为 false,则任何服务器都可以声称从您的域发送电子邮件。
  • valid: 记录解析正确吗? SPF 记录打破时 超过 10 个 DNS 查找限制或包含语法错误。
  • all_policy: 尾随机制。 -all (硬失败)是 最强设定。 ~all (软失败)将未经授权的邮件标记为 可疑。 +all 完全违背了SPF的目的。

健康 SPF 记录的 API 响应示例:

DMARC(基于域的消息身份验证、报告和一致性)

DMARC 告诉接收服务器当 SPF 或 DKIM 检查失败时要做什么。 没有它, 即使有效的 SPF 和 DKIM 记录也无法防止欺骗。

需要关注的关键领域:

  • policy:失败的消息会发生什么情况。 reject 滴 他们, quarantine 将它们发送到垃圾邮件, none 不采取任何行动 (仅监控)。
  • pct:策略适用的邮件百分比。 从低位开始 推出期间的数量,然后移至 100。
  • reporting.rua:发送汇总报告的位置。 没有这个,你 对身份验证失败没有可见性。

DMARC 记录的 API 响应示例:

DKIM(域名密钥识别邮件)

DKIM 向传出消息添加加密签名。 接收服务器验证 针对 DNS 中发布的公钥进行签名。 如果钥匙丢失或被旋转 如果不更新 DNS,签名验证会失败。

需要关注的关键领域:

  • has_dkim:是否为给定选择器发布了 DKIM 密钥? 每封电子邮件 提供者使用不同的选择器名称。
  • public_key_length:NIST 建议至少 2048 位。 按键更短 超过 1024 位被认为是弱的。
  • key_type:大多数密钥使用 RSA。 Ed25519 键更小、更快,但 邮件提供商的支持有限。

DKIM 检查的 API 响应示例:

按提供商列出的常见 DKIM 选择器

电子邮件提供商 DKIM 选择器
谷歌工作区 google
微软365 selector1, selector2
亚马逊SES 基于 UUID(检查您的 SES 仪表板)
Mailchimp/山魈 k1
发送网格 s1, s2
邮戳 每个域生成(检查 DNS 设置)

扩展工作流程

多个域

如果您管理多个域,请使用矩阵策略来检查每个域。 添加 botoi API 密钥作为 GitHub 秘密,以避免达到免费套餐速率限制。

Slack 失败通知

添加一个在任何检查失败时触发的通知步骤。 这使用了 官方 Slack GitHub 操作

Monorepo 设置

在 monorepo 中,您可能不希望每次推送时都运行 DNS 检查 包。 将触发器的范围限定为基础设施相关文件中的更改:

无论路径过滤器如何,计划的触发器仍然每天运行,因此您可以捕获 DNS 在存储库外部进行的更改。

使用 API 密钥实现更高的速率限制

如果您检查多个域或频繁运行工作流程,请添加您的 botoi API 密钥 作为 GitHub Actions 秘密:

  1. 转到您的存储库的“设置”> 秘密与变量> 行动
  2. 添加一个名为 BOTOI_API_KEY
  3. 将 auth 标头添加到每个 curl 命令中:

检查失败时该怎么办

  • 缺少 SPF 记录: 将 TXT 记录添加到您域的 DNS。 开始于 v=spf1 include:_spf.google.com ~all (将包含替换为您的 电子邮件提供商的 SPF 域)。
  • 无效的 SPF 记录: 您可能达到了 10 个 DNS 查找限制。 使用 替换 SPF 平整工具 include: 具有IP地址的机制, 或整合提供商。
  • 缺少 DMARC 记录: 添加 TXT 记录于 _dmarc.yourdomain.com。 开始于 v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com 监视 在执行之前。
  • DMARC 政策为“无”: 这在推出期间很好。 一旦您确认 合法电子邮件通过 SPF 和 DKIM,移至 p=quarantine 进而 p=reject
  • 缺少 DKIM 记录: 验证您的选择器是否正确 电子邮件提供商(参见上表)。 密钥必须作为 TXT 记录发布在 [selector]._domainkey.yourdomain.com
  • DKIM 密钥太短: 通过您的 DKIM 密钥将您的 DKIM 密钥旋转至 2048 位 电子邮件提供商的管理面板,然后更新 DNS TXT 记录。

FAQ

此工作流程是否需要 botoi API 密钥?
不需要。免费套餐每分钟允许 5 个请求,无需 API 密钥。 工作流每次运行发出 3 个请求(SPF、DMARC、DKIM),这在限制范围内。 如果您对多个域或选择器运行检查,请将您的 API 密钥添加为 GitHub 密钥并将其传递到授权标头中。
我可以在一次工作流程运行中检查多个域吗?
是的。 循环检查脚本中的域数组。 每个域需要 3 个 API 调用,因此免费层运行每次调用处理一个域。 对于多个域,添加 botoi API 密钥以避免速率限制。
我应该使用什么 DKIM 选择器?
选择器取决于您的电子邮件提供商。 Google Workspace 使用“google”,Microsoft 365 使用“selector1”和“selector2”,Amazon SES 使用基于 UUID 的选择器。 检查您的 DNS TXT 记录中是否有与模式 [selector]._domainkey.yourdomain.com 匹配的条目。
此工作流程会阻止我的部署吗?
仅当检查失败时,这意味着您的电子邮件安全记录丢失或配置错误。 这就是要点:您希望在这些问题导致可交付性问题之前发现它们。 您可以将工作流程更改为发布警告而不是失败,方法是将“exit 1”替换为创建 GitHub 问题或发送 Slack 消息的步骤。
我应该多久运行一次此检查?
每次推送到主分支时都是基线。 添加计划的 cron 触发器(例如,每天上午 9 点)以捕获存储库外部所做的 DNS 更改,例如当团队成员在注册商仪表板中编辑记录时。

开始使用 botoi 构建

150+ 个 API 端点,涵盖查询、文本处理、图片生成和开发者工具。免费套餐,无需信用卡。