- 网络安全
- 密码学
【免费下载链接】lego
Let's Encrypt/ACME client and library written in Go
lego 是一款用 Go 编写的 Let's Encrypt/ACME 客户端与库,其内置的 Infomaniak DNS 提供商(代码infomaniak,自 v4.1.0 起可用)允许你通过 Infomaniak 的域名管理 API 自动完成 DNS-01 挑战,从而为域名(含通配符域名)签发 TLS 证书。本文将围绕该提供商的官方文档展开,结合仓库源码深入讲解访问令牌的获取与权限要求、全部环境变量的含义与默认值、_FILE后缀的敏感信息注入方式,并剖析从创建 TXT 记录到清理记录的完整 API 调用链,帮助你既能在命令行中快速上手,也能以库的形式集成到自己的 Go 程序中。
快速开始:一行命令完成签发
Infomaniak 提供商的使用方式非常简洁——只需提供访问令牌,即可通过lego run子命令发起 DNS-01 挑战。以下是官方文档给出的标准示例:
INFOMANIAK_ACCESS_TOKEN=1234567898765432 \ lego run --dns infomaniak -d '*.example.com' -d example.com该命令的含义:
--dns infomaniak:指定使用 Infomaniak 作为 DNS-01 挑战的求解器(provider 代码即infomaniak);-d '*.example.com' -d example.com:同时为通配符域名*.example.com和根域名example.com申请证书。由于 DNS-01 挑战基于 DNS 记录验证域名控制权,因此天然支持通配符域名,这也是选择 DNS 挑战而非 HTTP/TLS 挑战的核心原因;- 通配符域名通常需要与根域名一起申请(ACME 协议对裸域与通配符域分别签发),示例中两者均会得到处理。
令牌通过环境变量INFOMANIAK_ACCESS_TOKEN注入。若缺少该变量,provider 初始化会直接失败(详见后文"错误排查"),因此务必在运行前正确导出。
获取访问令牌:所需权限与创建入口
Infomaniak 提供商的认证凭证是 API Access Token,创建入口为 Infomaniak 管理后台的令牌列表页面(https://manager.infomaniak.com/v3/ng/accounts/token/list)。
创建令牌时必须勾选以下两项权限,缺一不可:
dns:read:用于查询区域(zone)是否存在以及读取 DNS 记录信息;dns:write:用于创建和删除挑战用的 TXT 记录。
从源码看,令牌的认证方式为 OAuth2 静态 Bearer Token。在 client.go 中,OAuthStaticAccessToken函数通过oauth2.StaticTokenSource将令牌包装进 HTTP 客户端的 Transport,所有后续 API 请求都会携带Authorization: Bearer <token>头。测试用例 infomaniak_test.go 中的WithAuthorization("Bearer secret")也印证了这一点。
出于安全考虑,令牌应妥善保管。若需避免令牌出现在 shell 历史或进程列表中,可使用下文介绍的
_FILE后缀从文件中读取。
环境变量配置详解:必填凭证与可选参数
Infomaniak provider 的全部配置均通过环境变量传递,统一使用INFOMANIAK_命名空间前缀,这一点在 infomaniak.go 的常量定义中可以看到完整对应关系。
必填凭证(Credentials)
| 环境变量名 | 说明 |
|---|---|
INFOMANIAK_ACCESS_TOKEN | Infomaniak API 访问令牌 |
这是唯一必需的变量。infomaniak.go 中的NewDNSProvider()会调用env.Get(EnvAccessToken)读取该变量,缺失时返回错误infomaniak: some credentials information are missing: INFOMANIAK_ACCESS_TOKEN(对应测试 infomaniak_test.go)。
附加配置(Additional Configuration)
以下变量均可选,未设置时使用默认值。默认值与源码 infomaniak.go 中NewDefaultConfig()的实现完全一致:
| 环境变量名 | 说明 | 默认值 |
|---|---|---|
INFOMANIAK_ENDPOINT | API 端点地址 | https://api.infomaniak.com |
INFOMANIAK_HTTP_TIMEOUT | API 请求超时时间(秒) | 30 |
INFOMANIAK_POLLING_INTERVAL | DNS 传播检查的时间间隔(秒) | 10 |
INFOMANIAK_PROPAGATION_TIMEOUT | 等待 DNS 传播的最长时间(秒) | 120 |
INFOMANIAK_TTL | 挑战 TXT 记录的 TTL(秒) | 300 |
逐一说明其作用与源码依据:
INFOMANIAK_ENDPOINT:覆盖默认 API 地址。默认值https://api.infomaniak.com定义在 client.go 的DefaultBaseURL常量中。该变量主要服务于代理场景或 API 网关测试,一般无需修改;INFOMANIAK_HTTP_TIMEOUT:单个 API 请求的超时上限。源码中通过env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second)设置到http.Client.Timeout。当 Infomaniak API 响应缓慢时,可适当调大该值避免请求被过早中断;INFOMANIAK_POLLING_INTERVAL与INFOMANIAK_PROPAGATION_TIMEOUT:共同控制"等待 TXT 记录在全球 DNS 中传播"这一环节。源码 infomaniak.go 的Timeout()方法将PropagationTimeout与PollingInterval返回给 lego 的挑战调度器:每POLLING_INTERVAL秒查询一次解析结果,直到超过PROPAGATION_TIMEOUT仍未生效则判为失败。TXT 记录生效通常需要数秒到数十秒,若你的解析环境较慢,可适当调大传播超时;INFOMANIAK_TTL:创建 TXT 记录时使用的 TTL 值。较短的 TTL(如 60)能让记录更快在全球缓存中刷新,但示例与默认值均为 300 秒,属于通用安全取值。
使用_FILE后缀注入敏感信息
官方文档明确指出:上述所有环境变量名都可以追加_FILE后缀,以"文件路径"代替"直接值",即变量内容从指定文件中读取。这一机制在 docs/content/dns/_index.md 的Configuration and Credentials章节有通用说明,适用于包括 Infomaniak 在内的所有 DNS 提供商。
例如,将令牌写入文件后这样使用:
echo -n '1234567898765432' > /path/to/infomaniak-token INFOMANIAK_ACCESS_TOKEN_FILE=/path/to/infomaniak-token \ lego run --dns infomaniak -d '*.example.com' -d example.com注意:文件内容应只包含值本身(不要包含换行符或额外字符)。这种方式适合与密钥管理系统、Docker Secret 或 systemdEnvironmentFile配合使用,避免令牌明文出现在命令行参数或 shell 历史中。
源码剖析:DNS-01 挑战的完整调用链
Infomaniak provider 的实现在 infomaniak.go,底层 API 客户端在 internal/client.go,数据结构定义在 internal/types.go。整个挑战过程围绕Present(创建记录)与CleanUp(删除记录)两个钩子展开。
1. 自动探测区域(Zone)
Present的第一步是确定待挑战域名所属的 DNS 区域。infomaniak.go 的findZone方法从完整域名逐级向上尝试(例如先查_acme-challenge.example.com,再查example.com),对每一级调用ZoneExists检查区域是否存在,找到即返回。
对应的 API 是GET /2/zones/{zone}/exists(见 client.go)。值得一提的是,当 API 返回object_not_found错误时,客户端会将其视为"区域不存在"而不是异常(client.go),这正是逐级探测得以实现的基础。
2. 创建挑战 TXT 记录(Present)
确定区域后,Present会:
- 通过
dns01.GetChallengeInfo计算挑战值value(由 key authorization 派生); - 通过
dns01.ExtractSubDomain从 FQDN 中剥离区域名,得到子域前缀(例如_acme-challenge); - 构造
RecordRequest{Source, Target, TTL, Type: "TXT"}(结构体定义见 types.go),调用CreateRecord创建记录。
CreateRecord对应的 API 是POST /2/zones/{zone}/records?with=idn(见 client.go),其中with=idn参数用于启用国际化域名(IDN)支持。请求体示例可见测试夹具 record_create-request.json:
{ "source": "_acme-challenge", "target": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY", "ttl": 300, "type": "TXT" }创建成功后,客户端将记录 ID 与挑战令牌(token)以映射形式缓存在 provider 中(zones与recordIDs两个 map,配合互斥锁保证并发安全),供后续清理阶段使用。
3. 等待传播与验证
记录创建完成后,lego 会按照Timeout()返回的超时/间隔参数轮询 DNS 解析结果,确认 TXT 记录已全球生效后,才向 ACME 服务器提交挑战完成验证。这一步完全由 lego 的挑战调度框架处理,provider 只负责"创建记录"和"上报超时参数"。
4. 清理挑战记录(CleanUp)
验证完成后,lego 调用CleanUp删除临时 TXT 记录。infomaniak.go 先根据 token 从缓存中取出区域与记录 ID,再调用DeleteRecord执行DELETE /2/zones/{zone}/records/{record}(见 client.go),实现挑战记录的及时清理,避免残留记录造成安全隐患。
5. 测试用例验证
仓库提供了基于 mock 服务器的完整测试,可在无真实账号的情况下验证整个调用链。测试 TestDNSProvider_Present 依次 mock 了以下请求序列,与上述流程一一对应:
GET /2/zones/_acme-challenge.example.com/exists→ 返回 404(该区域不存在,继续向上探测);GET /2/zones/example.com/exists→ 返回{"result":"success","data":true}(区域存在);POST /2/zones/example.com/records?with=idn→ 返回新记录(ID 为 32824,见 record_create.json)。
同时 TestDNSProvider_CleanUp 验证了清理阶段对DELETE /2/zones/example.com/records/32824的调用。这些测试既是回归保障,也清晰地展示了 provider 与 Infomaniak API 之间的全部交互契约。
以 Go 库形式集成到自己的程序中
除了 CLI,你还可以将 lego 作为库使用,在自己的 Go 程序中直接驱动 Infomaniak provider。入口有两个:
NewDNSProvider():从环境变量读取配置并初始化(要求INFOMANIAK_ACCESS_TOKEN已设置);NewDNSProviderConfig(config *Config):以编程方式传入配置,适用于配置来自配置文件或参数的场景。
Config结构体(见 infomaniak.go)包含APIEndpoint、AccessToken、PropagationTimeout、PollingInterval、TTL、HTTPClient六个字段。其中HTTPClient允许你注入自定义的http.Client(如带代理、自定义 TLS 或复用连接池),默认超时 30 秒。测试中的mockBuilder(infomaniak_test.go)展示了标准用法:构造NewDefaultConfig()、设置APIEndpoint为测试服务器地址、填入令牌、再交给NewDNSProviderConfig。
集成后,将 provider 实例挂载到 lego 的Certificater/resolver流程中,即可复用Present/CleanUp完成 DNS-01 挑战的自动化。
常见错误与排查建议
结合源码中的错误路径,列出几类高频问题:
- 缺少令牌:未设置
INFOMANIAK_ACCESS_TOKEN时报infomaniak: some credentials information are missing: INFOMANIAK_ACCESS_TOKEN(NewDNSProvider路径);若通过NewDNSProviderConfig传入空令牌则报infomaniak: missing access token(见 infomaniak.go)。确认令牌已正确导出或写入配置; - 权限不足:创建令牌时未勾选
dns:read/dns:write,API 会返回权限相关错误(APIError结构见 types.go,错误信息会携带code与description)。回到令牌管理页面补全权限后重新生成令牌; - 区域找不到:报
zone not found for domain: <fqdn>(见 infomaniak.go),说明该域名不在当前 Infomaniak 账号下,或域名未正确配置为 Infomaniak 管理的 DNS 区域。请先在管理后台确认域名归属; - 传播超时:若频繁出现"等待传播超时",可适当增大
INFOMANIAK_PROPAGATION_TIMEOUT,或减小INFOMANIAK_TTL以加快记录刷新; - API 请求失败:检查
INFOMANIAK_ENDPOINT是否被误设为不可达地址,以及网络代理是否能访问 Infomaniak API。
总结
Infomaniak 是 lego 内置 DNS 提供商之一,只需一枚具备dns:read/dns:write权限的访问令牌,即可借助lego run --dns infomaniak一条命令完成通配符证书的自动化签发。其实现以Present/CleanUp两个钩子为核心,底层通过ZoneExists、CreateRecord、DeleteRecord三个 API 端点完成"探测区域 → 创建 TXT → 等待传播 → 清理记录"的完整闭环,且对超时、轮询、TTL 等关键行为提供了可调参数。无论是 CLI 用户还是库集成开发者,都可以依据本文的配置表与源码调用链快速落地,并在遇到问题时按图索骥完成排查。
- 网络安全
- 密码学
【免费下载链接】lego
Let's Encrypt/ACME client and library written in Go
相关推荐
Dyn DNS 提供商接入指南:用 lego 通过 DNS-01 挑战签发通配符证书
Dyn DNS 提供商接入指南:用 lego 通过 DNS 01 挑战签发通配符证书 本指南以 lego 项目自动生成的 Dyn 提供商文档( docs/con
网络安全密码学Midday 循环发票系统全解:调度生成、幂等保障与时区一致的实现
Midday 循环发票系统全解:调度生成、幂等保障与时区一致的实现 本文以 Midday 仓库中的循环发票(Recurring Invoice)系统文档为主线,
网络安全密码学AI SDK Cartesia Provider 能力全景:Sonic 语音合成与 Ink 2 实时转录的版本演进与源码级解析
AI SDK Cartesia Provider 能力全景:Sonic 语音合成与 Ink 2 实时转录的版本演进与源码级解析 @ai sdk/cartesia
网络安全密码学
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考