- 网络安全
- 密码学
【免费下载链接】lego
Let's Encrypt/ACME client and library written in Go
本文是 lego(Let's Encrypt/ACME client,使用 Go 编写)官方文档中 Ionos Cloud DNS 提供者的中文技术指南。文章以 docs/content/dns/zz_gen_ionoscloud.md 为核心骨架,结合 providers/dns/ionoscloud 目录下的源码与测试进行深度展开,帮助读者在 lego 中配置 Ionos Cloud(Ionos 云)DNS 服务,通过 DNS-01 挑战完成通配符证书签发,并理解其底层实现机制。
- 提供者代码(Code):
ionoscloud - 引入版本(Since):v4.30.0
- 官方服务:Ionos Cloud DNS(Cloud DNS 管理界面)
- API 文档:Ionos Cloud DNS API v1
快速上手:一条命令完成通配符证书签发
在 lego 中使用 Ionos Cloud 作为 DNS 挑战提供者的最小命令如下(原文档示例):
IONOSCLOUD_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \ lego run --dns ionoscloud -d '*.example.com' -d example.com命令语义拆解:
IONOSCLOUD_API_TOKEN:Ionos Cloud API 令牌,用于通过Authorization: Bearer <token>头对 DNS API 进行认证(见 providers/dns/ionoscloud/internal/client.go);--dns ionoscloud:指定使用 DNS-01 挑战及 Ionos Cloud 提供者;-d '*.example.com' -d example.com:同时请求通配符域名与裸域证书——由于 ACME 通配符挑战只能通过 DNS-01 完成,这正是此类 DNS 提供者最典型的使用场景。
注意:原文档命令中
-d '*.example.com'表示申请的是通配符证书,-d example.com是为了让证书同时覆盖裸域。两个域名共用同一个_acme-challenge验证流程,Ionos Cloud 提供者会分别在所属 DNS zone 中写入对应的 TXT 记录。
使用前准备
- 登录 Ionos Cloud 控制台(Cloud DNS 服务),创建并启用托管 DNS zone(如
example.com),并将域名的 NS 记录指向 zone 中显示的 nameservers(见 zones.json 测试夹具 中形如ns-ic.ui-dns.com的 NS 列表); - 在 Ionos Cloud 的 API 密钥管理界面生成 API token(需具备 DNS zone 读写权限);
- 在 shell 环境中导出
IONOSCLOUD_API_TOKEN,即可运行 lego 命令。
凭证配置(Credentials)
Ionos Cloud 提供者需要且仅需要一个凭证环境变量:
| 环境变量名 | 说明 |
|---|---|
IONOSCLOUD_API_TOKEN | API token,用于调用 Ionos Cloud DNS API |
这一约束在源码中有明确体现:NewDNSProvider()通过env.Get(EnvAPIToken)读取变量,缺失时会返回ionoscloud: some credentials information are missing: IONOSCLOUD_API_TOKEN错误(见 ionoscloud.go),对应的缺失凭证测试用例见 ionoscloud_test.go。而NewDNSProviderConfig()在 API token 为空时会直接返回ionoscloud: credentials missing(见 internal/client.go)。
使用_FILE后缀从文件读取凭证
lego 的 DNS 提供者统一支持"环境变量名 +_FILE"后缀,将变量值替换为指向凭证文件的路径(详见 docs/content/dns/_index.md 的"Configuration and Credentials"章节)。原文档特别提示:所有环境变量(含下文附加配置项)均可追加_FILE后缀引用文件而非直接引用值。
IONOSCLOUD_API_TOKEN_FILE=/path/to/ionoscloud-token \ lego run --dns ionoscloud -d '*.example.com' -d example.com其中/path/to/ionoscloud-token文件内容应仅包含 token 值本身(不含换行符以外的任何多余内容)。这在需要将敏感信息与命令行历史、CI 日志隔离的场景下尤为实用。
附加配置项(Additional Configuration)
原文档给出了四个可选配置环境变量,均可通过IONOSCLOUD_前缀在 CLI 或程序化配置中设置:
| 环境变量名 | 说明 | 默认值 |
|---|---|---|
IONOSCLOUD_HTTP_TIMEOUT | API 请求超时时间(秒) | 30 |
IONOSCLOUD_POLLING_INTERVAL | DNS 传播检查的轮询间隔(秒) | 2 |
IONOSCLOUD_PROPAGATION_TIMEOUT | DNS 传播的最大等待时间(秒) | 120 |
IONOSCLOUD_TTL | DNS 挑战所用 TXT 记录的 TTL(秒) | 120 |
以上默认值在NewDefaultConfig()中通过platform/env包读取并回退到内置默认值(见 ionoscloud.go):
IONOSCLOUD_TTL:默认取dns01.DefaultTTL(120 秒);IONOSCLOUD_PROPAGATION_TIMEOUT:默认 120 秒;IONOSCLOUD_POLLING_INTERVAL:默认取dns01.DefaultPollingInterval(2 秒);IONOSCLOUD_HTTP_TIMEOUT:默认 30 秒,作用于底层http.Client的超时。
各配置项的实际影响
IONOSCLOUD_TTL:决定Present()阶段写入的 TXT 记录 TTL。该值直接进入 API 请求体(见 ionoscloud.go),测试夹具中对应请求为"ttl": 120(见 create_record-request.json)。TTL 越小,权威 DNS 缓存越早失效,验证速度越快,但会略微增加 DNS 查询压力;IONOSCLOUD_PROPAGATION_TIMEOUT与IONOSCLOUD_POLLING_INTERVAL:通过DNSProvider.Timeout()返回给 lego 的传播等待机制(见 ionoscloud.go),两者共同决定"写入 TXT 后轮询 DNS 解析结果"的总时长与节奏。当实际 DNS 生效较慢时可适当调大PROPAGATION_TIMEOUT;IONOSCLOUD_HTTP_TIMEOUT:限制单次 API 调用的最长耗时,避免网络异常时请求无限挂起。
程序化配置(作为 Go 库使用)
Ionos Cloud 提供者同样支持以库方式集成。NewDNSProvider()从环境变量自动装配配置,而NewDNSProviderConfig()允许显式传入Config结构体:
import ( "github.com/go-acme/lego/v5/challenge/dns01" "github.com/go-acme/lego/v5/providers/dns/ionoscloud" "github.com/go-acme/lego/v5/lego" "github.com/go-acme/lego/v5/registration" ) config := ionoscloud.NewDefaultConfig() config.APIToken = "your-api-token" config.TTL = 120 config.PropagationTimeout = 120 * time.Second config.PollingInterval = 2 * time.Second provider, err := ionoscloud.NewDNSProviderConfig(config) if err != nil { log.Fatal(err) } client := lego.NewClient(lego.NewConfig(account)) client.Challenge.SetDNS01Provider(provider, dns01.CNAMEOption(true))其中Config结构体字段与上面四类环境变量一一对应(见 ionoscloud.go),便于在代码中直接注入自定义http.Client(例如设置代理或自定义 TLS 配置)。
源码级原理:DNS-01 挑战的完整调用链
从源码结构看,Ionos Cloud 提供者的工作流程可以划分为四个阶段,分别由Present/CleanUp/Timeout三个接口方法与内部 API 客户端完成(见 ionoscloud.go)。
阶段一:定位 DNS zone
Present()首先通过dns01.GetChallengeInfo()计算挑战 FQDN(如_acme-challenge.example.com),随后调用FindZoneByFqdn()找到所属权威 zone,并向 Ionos Cloud DNS API 发起GET /zones?filter.zoneName=<zone>请求精确匹配 zone 名称(见 internal/client.go)。若匹配结果数量不为 1,会返回zone ID not found for domain错误——因此请确保托管 zone 名称与域名完全一致。
对应的测试用例TestDNSProvider_Present严格校验了请求路径GET /zones、查询参数filter.zoneName=example.com以及响应夹具 zones.json(见 ionoscloud_test.go)。
阶段二:创建 TXT 验证记录
定位到 zone 后,Present()计算子域名(_acme-challenge)并构造记录属性:
request := internal.RecordProperties{ Name: subDomain, // 例如 _acme-challenge Type: "TXT", Content: info.Value, // 挑战 token 值 TTL: d.config.TTL, // 默认 120 }然后调用POST /zones/{zoneID}/records创建记录(见 internal/client.go)。请求体结构由 create_record-request.json 给出,RecordProperties的 JSON 映射定义在 internal/types.go。
创建成功后,Present()会把token → zoneID / recordID的映射缓存到内存中(由sync.Mutex保护,见 ionoscloud.go),供后续清理阶段使用。
阶段三:等待 DNS 传播
lego 的 DNS-01 求解器会反复查询权威/递归 DNS,确认 TXT 记录生效后才向 ACME 服务器发起验证请求。Timeout()返回(PropagationTimeout, PollingInterval)控制这一过程的整体上限与轮询频率(见 ionoscloud.go),对应IONOSCLOUD_PROPAGATION_TIMEOUT(默认 120 秒)与IONOSCLOUD_POLLING_INTERVAL(默认 2 秒)。
阶段四:清理 TXT 记录
证书签发完成后,CleanUp()根据token从缓存中取出 zoneID 与 recordID,调用DELETE /zones/{zoneID}/records/{recordID}删除验证记录(见 internal/client.go),并同步清理内存缓存(见 ionoscloud.go)。对应测试TestDNSProvider_CleanUp通过 mock 服务器验证了DELETE请求路径与 202 响应处理(见 ionoscloud_test.go)。
API 通信细节
- Base URL:
https://dns.de-fra.ionos.com(见 internal/client.go),测试中通过p.client.BaseURL替换为 mock 服务器地址; - 认证方式:每个请求携带
Authorization: Bearer <apiKey>头(见 internal/client.go),mock 测试也校验了该头(servermock.CheckHeader().WithAuthorization("Bearer secret"),见 ionoscloud_test.go); - 错误处理:非 2xx 响应会解析
httpStatus与messages[].errorCode/error/message结构并包装为APIError(见 internal/client.go 与 internal/types.go),便于定位 token 失效、zone 不存在等具体原因; - 请求头:统一设置
Accept: application/json,携带 payload 时设置Content-Type: application/json(见 internal/client.go)。
常见问题排查
| 现象 | 可能原因与排查方向 |
|---|---|
ionoscloud: some credentials information are missing: IONOSCLOUD_API_TOKEN | 未设置IONOSCLOUD_API_TOKEN或_FILE指向的文件为空(见 ionoscloud_test.go) |
ionoscloud: zone ID not found for domain ... | 托管 zone 名称与目标域名不一致,或GET /zones过滤后匹配到 0 个/多个 zone |
ionoscloud: could not find zone for domain ... | 域名在公共 DNS 中尚未解析到 Ionos Cloud 的 NS,请检查域名 NS 记录是否已切换到 zone 的 nameservers |
| 等待验证超时 | 适当调大IONOSCLOUD_PROPAGATION_TIMEOUT,或确认 TXT 记录写入后权威 DNS 的生效速度 |
| API 返回 4xx/5xx | 检查 token 权限(需 zone 读写)、zone 是否处于enabled状态,以及是否触发了 API 限流 |
进一步阅读
- 提供者配置元数据(本文档的生成来源):providers/dns/ionoscloud/ionoscloud.toml
- 提供者核心实现:providers/dns/ionoscloud/ionoscloud.go
- API 客户端与类型定义:providers/dns/ionoscloud/internal/client.go、providers/dns/ionoscloud/internal/types.go
- 单元测试与测试夹具:providers/dns/ionoscloud/ionoscloud_test.go、providers/dns/ionoscloud/internal/fixtures
- 全局环境变量/
_FILE约定:docs/content/dns/_index.md - DNS 提供者注册与列表:providers/dns/zz_gen_dns_providers.go
本文所有默认值、环境变量与调用链均以当前仓库代码为准;使用不同 lego 版本时请以对应版本源码及官方文档为准。
- 网络安全
- 密码学
【免费下载链接】lego
Let's Encrypt/ACME client and library written in Go
相关推荐
lego 使用 CPanel/WHM DNS Provider 自动签发 Let's Encrypt 证书:配置指南与源码原理解析
lego 使用 CPanel/WHM DNS Provider 自动签发 Let's Encrypt 证书:配置指南与源码原理解析 CPanel/WHM 是虚拟
网络安全密码学lego 使用 FENO DNS 提供商签发证书:配置、原理与源码解析
lego 使用 FENO DNS 提供商签发证书:配置、原理与源码解析 本文基于 lego(Let's Encrypt/ACME 客户端与 Go 库)仓库中 F
网络安全密码学Tool Updater
Tool Updater Checks for and applies Homebrew updates to beads bd and dolt . gt i
网络安全密码学
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考