Certimate:把ACME协议翻译成人话的Go证书管家

7 次阅读 0 点赞 0 评论 9 分钟原创开源项目

Certimate是一个自托管、零依赖、仅16MB内存占用的Go语言ACME工具,通过工作流引擎+插件化Provider设计,支持60+ DNS服务商与110+部署目标,将SSL证书全生命周期(申请/验证/部署/续期/监控)可视化自动化。它不依赖数据库或Redis,单二进制即可运行,是运维与DevOps团队真正能‘开箱即用’的证书基础设施。

#ssl #acme #certificates #devops #go #automation #security
Certimate:把ACME协议翻译成人话的Go证书管家

大家好,我是周小码——一个被Spring Boot自动配置绕晕过三次、被Kubernetes YAML文件背刺过五次的Java老兵。今天不聊Java,咱们来拆解一个让我眼前一亮的Go项目:Certimate

你有没有在凌晨三点被钉钉弹窗惊醒?点开一看:[ALERT] shop.cn SSL certificate expires in 2h。你猛灌一口冰美式,翻出certbot文档,手抖着敲下--manual,然后盯着DNS TXT记录生效倒计时,祈祷阿里云DNS别又限流……这种场景,不是故事,是很多SRE和全栈开发者的日常。

而Certimate,就是那个默默站在你身后、把ACME协议翻译成人话、把DNS挑战变成拖拽流程的运维界‘懂王’。

架构:工作流引擎 + 插件化Provider,不是硬编码,是抽象力

Certimate没写死Cloudflare或腾讯云的SDK调用。它只定义两个核心接口:

go 复制代码
// pkg/provider/dns.go
type DNSProvider interface {
	Apply(domain string, value string) error
	Clean(domain string, value string) error
	Present(domain string, value string) error // 创建TXT记录
	Cleanup(domain string, value string) error   // 清理TXT记录
}
go 复制代码
// pkg/provider/hosting.go
type HostingProvider interface {
	Deploy(domain string, certBytes, keyBytes []byte) error
	Rollback(domain string) error
	Status(domain string) (string, error)
}

所有60+ DNS服务商(阿里云、Cloudflare、Namecheap……)和110+部署目标(K8s Ingress、Nginx、Caddy、SLB、TKE、AWS ALB……)都作为独立插件实现这两个接口。主流程完全解耦——调度器(Workflow Engine)只认apply → verify → deploy → notify四个阶段,不关心你是调API还是改配置文件。

这就像当年我重构支付系统时拆出的‘渠道适配层’:支付宝、微信、PayPal各写各的,主流程只调pay()refund()。Certimate的调度器就是那个‘支付网关’,它把ACME的复杂性封装成可编排、可观测、可重试的状态机。

硬核细节:为什么它只要16MB内存?

看它的启动逻辑(cmd/certimate/main.go):

go 复制代码
func main() {
	// 零外部依赖:SQLite仅作可选持久化,默认纯内存Map存储任务状态
	state := NewInMemoryState() // goroutine-safe map[string]*Task

	// HTTP服务直接用net/http,无Gin/Echo等框架开销
	http.Handle("/api/", api.NewRouter(state))
	http.Handle("/", http.FileServer(http.FS(static.EmbeddedFS)))

	log.Printf("✅ Certimate started on :8090, memory usage: ~16MB")
	http.ListenAndServe(":8090", nil)
}

没有嵌入式Tomcat,没有HikariCP连接池,没有Lettuce Redis客户端——只有net/http + sync.Map + 可选SQLite(仅用于审计日志持久化)。ACME密钥对全程在内存生成(crypto/ecdsa.GenerateKey),证书私钥绝不落盘,除非你显式启用--db-path

这就是Go静态编译+工程克制的威力:一个./certimate二进制,Linux/macOS/Windows通吃,strace ./certimate serve能看到它只open了/dev/urandom/proc/self/stat,连/etc/resolv.conf都懒得读——DNS解析全走Go原生net.Resolver

实战:10分钟搞定*.api.example.com的K8s Ingress证书

别光听我说,上手试试:

Step 1:Docker一键生产部署(带时区、数据卷、自动重启)

bash 复制代码
## 注意:-v $(pwd)/data:/app/pb_data 是关键,证书/配置/日志全落在此目录
docker run -d \
  --name certimate \
  --restart unless-stopped \
  -p 8090:8090 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /etc/timezone:/etc/timezone:ro \
  -v $(pwd)/data:/app/pb_data \
  certimate/certimate:latest

Step 2:访问 http://localhost:8090,注册admin账号(首次访问自动引导)

Step 3:新建Workflow,填以下7步(真实UI路径):

  1. Certificate Provider → Let's Encrypt (Production)
  2. Challenge Type → DNS-01
  3. DNS Provider → Alibaba Cloud(填AccessKey ID/Secret,权限只需AlidnsFullAccess
  4. Domain → *.api.example.com
  5. Hosting Provider → Kubernetes(上传~/.kube/config,或填ServiceAccount Token)
  6. Target Resource → Ingress(命名空间+Ingress名)
  7. Save & Run

Certimate立刻执行:

  • ✅ 生成ECDSA P-256密钥对
  • ✅ 调用阿里云DNS API创建_acme-challenge.api.example.com TXT记录
  • ✅ 轮询dig TXT _acme-challenge.api.example.com +short,等待TTL生效(默认30s超时)
  • ✅ 向Let's Encrypt ACME v2 endpoint发起newOrderfinalize
  • ✅ 下载PEM证书链,base64编码后PATCH到Ingress的tls[].secretName对应Secret

整个过程在Web UI里实时显示每一步耗时、HTTP状态码、响应体片段。失败?它会高亮报错行:“❌ DNS query timeout after 5 attempts — check if Aliyun DNS API quota exhausted”。

踩坑指南:那些README没明说但你会撞上的墙

  • 问题:K8s集群内网无法解析公网DNS(如acme-v02.api.letsencrypt.org
    解法:在Certimate容器内加--dns=8.8.8.8,或修改K8s CoreDNS配置添加上游转发

  • 问题:阿里云DNS返回InvalidDomainName,但域名明明注册了
    解法:Certimate要求域名必须已在阿里云DNS控制台“添加域名”,不能只靠API创建——这是阿里云OpenAPI的限制,非Bug

  • 问题:续期时提示order already finalized,但证书未更新
    解法:Certimate默认复用ACME Order(节省Rate Limit),但某些CA会拒绝重复finalize。手动进入/app/pb_data/workflows/xxx.json,删掉order_url字段再重试

我的真实评价

它不是银弹。不支持ACME revoke原子操作;多租户隔离还在Roadmap;暂未集成Vault或HashiCorp Consul作为密钥后端。但它做对了一件事:把SSL证书从‘基础设施里的基础设施’,变成了‘点几下就能跑通’的业务能力

市场部同事能给自己部门的test.marketing.example.com配证书;前端工程师能给本地dev.localhost跑通HTTPS调试;SRE终于不用半夜爬起来修shell脚本了。

如果明天我要上线一个新SaaS产品,我会把Certimate放进~/bin/,和kubectlcurljq并列。它不是最炫的,但可能是今年最值得你花10分钟部署的那颗子弹。

别再让证书过期报警把你从被窝拽出来了。

最后更新:2026-03-19T10:01:38

评论 (0)

发表评论

blog.comments.form.loading
0/500
加载评论中...