使用 lego 与 Core-Networks DNS 提供商签发通配符证书:环境变量配置与源码级原理解析
2026/9/24 16:20:35 网站建设 项目流程
  • 网络安全
  • 密码学

【免费下载链接】lego

Let's Encrypt/ACME client and library written in Go

项目地址:https://gitcode.com/gh_mirrors/le/lego
点击查看免费下载

导读

Core-Networks(code:corenetworks)是 lego 内置的 DNS-01 挑战提供商之一,用于通过 Core-Networks 的 DNS 托管 API 自动添加/删除_acme-challengeTXT 记录,从而为域名(含通配符)签发 Let's Encrypt 证书。本文以官方配置文档为主体,结合仓库源码深入讲解凭据与超时参数的配置方式、_FILE环境变量文件注入机制、DNS-01 挑战的完整调用链,以及如何在 Go 程序中以库的形式集成该提供商。

一、提供商概览

Core-Networks 提供商自v4.20.0起被引入 lego,其注册入口位于 providers/dns/zz_gen_dns_providers.go,通过环境变量加载并调用corenetworks.NewDNSProvider()。提供商元数据定义在 providers/dns/corenetworks/corenetworks.toml,而对应的生成文档即 docs/content/dns/zz_gen_corenetworks.md。

与 HTTP-01 需要 80 端口回源不同,DNS-01 挑战通过在 DNS 中写入 TXT 记录来完成验证,因此特别适合:

  • 签发通配符证书(如*.example.com);
  • 服务器无法对外开放 80/443 端口的场景;
  • 需要为大量子域一次性签发的自动化场景。

使用该提供商前,你需要一个可用的 Core-Networks API 账号(用户名 + 密码),并将待签发域名托管在其 DNS 平台。

二、快速开始:一条命令完成签发

官方文档给出的最小可用示例是通过环境变量注入凭据后直接运行lego run

CORENETWORKS_LOGIN="xxxx" \ CORENETWORKS_PASSWORD="yyyy" \ lego run --dns corenetworks -d '*.example.com' -d example.com

命令说明:

  • --dns corenetworks:指定使用 Core-Networks 提供商执行 DNS-01 挑战;
  • -d '*.example.com':申请通配符证书;
  • -d example.com:同时申请裸域证书(Let's Encrypt 的通配符证书不覆盖裸域,二者需分别签发)。

签发成功后,证书与私钥默认保存在./.lego/certificates/目录下(可通过 lego 的--path等参数调整存储位置)。该示例同样记录在配置元数据文件 corenetworks.toml 的Example字段中,是官方验证过的可运行形态。

三、凭据配置(Credentials)

3.1 环境变量

Core-Networks 提供商需要两个必填凭据:

环境变量名说明
CORENETWORKS_LOGINAPI 账号的用户名
CORENETWORKS_PASSWORDAPI 账号的密码

环境变量常量定义在 providers/dns/corenetworks/corenetworks.go:

const ( envNamespace = "CORENETWORKS_" EnvLogin = envNamespace + "LOGIN" EnvPassword = envNamespace + "PASSWORD" // ... )

NewDNSProvider()中通过env.Get(EnvLogin, EnvPassword)统一读取(corenetworks.go),任一凭据缺失都会返回形如corenetworks: some credentials information are missing: CORENETWORKS_LOGIN的错误。这一点在 corenetworks_test.go 的TestNewDNSProvider用例中有完整验证(分别覆盖"缺 login"与"缺 password"两种失败路径)。

3.2 使用 _FILE 后缀注入凭据(Docker/容器场景)

所有环境变量名都可以追加_FILE后缀,改为从文件中读取值,例如CORENETWORKS_PASSWORD_FILE=/run/secrets/cn_password。该机制由 platform/env/env.go 的GetOrFile实现:

  1. 优先读取CORENETWORKS_PASSWORD环境变量;
  2. 若为空,则读取CORENETWORKS_PASSWORD_FILE指向的文件内容;
  3. 读取成功后使用strings.TrimRight(fileContents, "\r\n")去除末尾换行符。

这一特性特别适合 Docker Secret、Kubernetes Secret 挂载等不允许把密码写进环境变量明文或镜像层的部署场景。所有附加配置项同样支持_FILE后缀,通用说明见文档 docs/content/dns/_index.md 中"Configuration and Credentials"一节。

四、附加配置项详解(Additional Configuration)

Core-Networks 提供商还支持 5 个可选环境变量,用于控制超时、探测频率与记录 TTL:

环境变量名说明默认值
CORENETWORKS_HTTP_TIMEOUTAPI 请求超时时间(秒)30
CORENETWORKS_POLLING_INTERVALDNS 传播检查间隔(秒)2
CORENETWORKS_PROPAGATION_TIMEOUTDNS 传播最大等待时间(秒)60
CORENETWORKS_SEQUENCE_INTERVAL顺序请求之间的间隔(秒)60
CORENETWORKS_TTL用于挑战的 TXT 记录 TTL(秒)3600

这些参数的默认值在 NewDefaultConfig 中设定,并与 lego 的dns01包内置常量衔接:

func NewDefaultConfig() *Config { return &Config{ TTL: env.GetOrDefaultInt(EnvTTL, 3600), PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout), PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval), SequenceInterval: env.GetOrDefaultSecond(EnvSequenceInterval, dns01.DefaultPropagationTimeout), HTTPClient: &http.Client{ Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), }, } }

源码实现细节值得注意:

  • 传播与轮询PropagationTimeoutPollingInterval通过Timeout()方法暴露给 lego 的挑战管理器(corenetworks.go),用于等待 TXT 记录在全球 DNS 生效;CORENETWORKS_PROPAGATION_TIMEOUT=60秒是等待上限,CORENETWORKS_POLLING_INTERVAL=2秒是每次探测的间隔。若你的权威 DNS 更新较慢,可适当调大传播超时。
  • 顺序模式Sequential()返回SequenceInterval(corenetworks.go),当一次签发多个域名(如通配符 + 裸域组合)时,lego 会按此间隔依次发起挑战,避免一次性并发请求过多导致限流。
  • TTL:写入 TXT 记录的 TTL,默认 3600 秒。更小的 TTL 可以缩短验证前的等待时间,但会略微增加 DNS 查询量。
  • HTTP 超时:所有 API 调用的客户端超时,默认 30 秒,通过CORENETWORKS_HTTP_TIMEOUT调整。

此外,所有数值型变量都经由env.GetOrDefaultSecond/env.GetOrDefaultInt解析,若变量值无法解析为数字,会静默回退到默认值(见 platform/env/env.go),因此配置错误时不会直接报错,需留意日志。

五、源码级原理:DNS-01 挑战的完整调用链

5.1 Present:添加验证记录

当 lego 发起 DNS-01 挑战时,会调用 provider 的Present方法(corenetworks.go),其流程为:

  1. 计算挑战信息:通过dns01.GetChallengeInfo(ctx, domain, keyAuth)得到_acme-challenge的完整域名(EffectiveFQDN)与待写入的 TXT 值(info.Value);
  2. 获取认证令牌:调用内部客户端的CreateAuthenticatedContext先向 Core-Networks API 换取 Bearer Token(见下节);
  3. 定位 DNS 区域:调用dns01.DefaultClient().FindZoneByFqdn根据 FQDN 逐级向上查找所属 Zone,例如_acme-challenge.example.com会定位到example.com区域;
  4. 计算子域名dns01.ExtractSubDomain从 FQDN 中剥离 Zone 得到记录名(如_acme-challenge);
  5. 构造并提交记录:构造TXT类型的Record{Name, TTL, Type, Data},先调用AddRecord添加记录,再调用CommitRecords提交变更。

5.2 CleanUp:验证完成后的清理

挑战验证成功后,CleanUp(corenetworks.go)执行逆向操作:同样先定位 Zone、计算子域名,然后调用DeleteRecords删除匹配的 TXT 记录,并再次CommitRecords提交。注意 Core-Networks API 的设计是"增删记录后必须显式 commit 才会真正生效",这也是Present/CleanUp都包含两步写操作的原因。

5.3 底层 API 客户端

内部客户端实现在 providers/dns/corenetworks/internal/client.go,默认 API 基址为https://beta.api.core-networks.dedefaultBaseURL,见 client.go),涉及的关键端点:

API 端点对应方法作用
POST /auth/tokenCreateAuthenticationToken用 login/password 换取令牌
GET /dnszonesListZone列出所有 DNS 区域
GET /dnszones/{zone}GetZoneDetails查询区域详情(含 DNSSEC、TSIG 等)
GET /dnszones/{zone}/recordsListRecords列出区域记录
POST /dnszones/{zone}/records/AddRecord添加记录
POST /dnszones/{zone}/records/deleteDeleteRecords删除匹配记录
POST /dnszones/{zone}/records/commitCommitRecords提交(生效)变更

认证令牌机制见 internal/identity.go:CreateAuthenticationTokenAuth{Login, Password}调用POST /auth/token,返回Token{Token, Expires},随后令牌被放入context.Context,每次请求通过do方法自动附加Authorization: Bearer <token>头(client.go)。请求响应非 2xx 状态码时会通过errutils包装为带状态码的明确错误。

记录与区域的数据结构定义在 internal/types.go:Record{Name, TTL, Type, Data}对应 API 的 TXT 记录;ZoneDetails还包含ActiveDNSSecTSIG等区域元信息。对应接口的请求/响应 JSON 示例可参考测试夹具目录 providers/dns/corenetworks/internal/fixtures 中的auth.jsonListZone.jsonListRecords.jsonGetZoneDetails.json

六、以库的形式集成到 Go 程序

若你并非使用 lego CLI,而是在 Go 项目中以库方式集成,可直接构建 provider 实例。最简方式是通过环境变量:

import "github.com/go-acme/lego/v5/providers/dns/corenetworks" provider, err := corenetworks.NewDNSProvider() if err != nil { log.Fatalf("create provider: %v", err) }

需要编程式控制参数时,使用NewDNSProviderConfig(corenetworks.go):

config := corenetworks.NewDefaultConfig() config.Login = "xxxx" config.Password = "yyyy" config.TTL = 300 config.PropagationTimeout = 90 * time.Second provider, err := corenetworks.NewDNSProviderConfig(config) if err != nil { log.Fatalf("create provider: %v", err) }

Config结构体(corenetworks.go)包含LoginPasswordPropagationTimeoutPollingIntervalSequenceIntervalTTL与可选的HTTPClient字段。校验规则:confignilLogin/Password任一为空时返回corenetworks: credentials missing。随后将provider交给lego客户端的ChallengeProvider即可参与完整的 ACME 订单流程。

七、测试与验证

仓库为该提供商提供了单元测试与实时测试两套验证手段:

  • corenetworks_test.go:TestNewDNSProviderTestNewDNSProviderConfig验证凭据缺失时的错误信息是否符合预期;
  • 同文件的TestLivePresent/TestLiveCleanUp(corenetworks_test.go)为实时测试:设置CORENETWORKS_LOGINCORENETWORKS_PASSWORD以及测试专用的CORENETWORKS_DOMAIN后运行,会真实调用 Core-Networks API 完成一次 TXT 记录的添加与删除,可用于在接入生产前验证账号权限与网络连通性;
  • 内部客户端层的接口测试与夹具校验位于 internal/client_test.go 与 internal/identity_test.go。

八、注意事项与排障建议

  • 通配符证书必须同时申请裸域:Let's Encrypt 签发的*.example.com不覆盖example.com,这也是官方示例同时传入两个-d参数的原因;
  • Zone 必须存在于账号下Present依赖FindZoneByFqdn找到 Zone,若域名未托管于 Core-Networks 或账号无该 Zone 权限,会返回could not find zone for domain错误;
  • 别忘记 commit:记录增删后必须提交(CommitRecords),直接修改 API 或跳过 commit 会导致变更不生效;
  • 敏感信息优先使用_FILE:在容器编排场景下,用CORENETWORKS_LOGIN_FILE/CORENETWORKS_PASSWORD_FILE从 Secret 文件注入凭据,避免凭据进入环境变量明文或镜像层;
  • 传播等待时间:TXT 记录生效需要时间,若频繁出现挑战超时,可适当调大CORENETWORKS_PROPAGATION_TIMEOUT并调小 TTL;
  • 多域签发限流:同时签发多个域名时,CORENETWORKS_SEQUENCE_INTERVAL控制顺序间隔,默认 60 秒,可按需调整以平衡速度与稳定性。

通过以上配置与源码分析,你应当能够独立完成 Core-Networks 托管域名的自动签发配置,并在出现异常时快速定位到具体的参数或调用环节。

  • 网络安全
  • 密码学

【免费下载链接】lego

Let's Encrypt/ACME client and library written in Go

项目地址:https://gitcode.com/gh_mirrors/le/lego
点击查看免费下载

相关推荐

上一篇:空洞骑士模组管理终极指南:Scarab让模组安装从未如此简单
下一篇:空洞骑士模组管理终极解决方案:Scarab让模组安装从未如此简单

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询