cert-ctrl 使用场景图解
使用场景 1:开发环境的自签名 CA
问题:手动 CA 分发
开发者需要在 localhost 上使用 HTTPS
↓
生成自签名 CA
↓
😫 在每台机器上手动操作:
↓
┌────────────────────────────────┐
│ 1. 复制 CA 证书文件 │
│ 2. 安装到信任存储 │
│ • Windows: certmgr.msc │
│ • Linux: update-ca-trust │
│ • macOS: Keychain Access │
│ 3. 配置每个应用程序 │
│ 4. CA 更改时重复以上步骤 │
└────────────────────────────────┘
↓
在 WSL/Docker 中仍然不工作?😭
再重复一遍所有步骤!
解决方案:自动化 CA 分发
┌──────────────────────────────────────┐
│ cert-ctrl 服务器 │
│ • 生成自签名 CA │
│ • 向已认证的代理提供 CA │
│ • 颁发开发证书 │
└──────┬───────────────────────────────┘
│
│ 代理认证并拉取 CA
│
├─────────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│Windows│ │ WSL │ │ SSH │ │Docker │
│ 宿主机│ │Ubuntu │ │远程 │ │ VM │
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
│ │ │ │
┌───▼────────────▼──────────────▼──────────────▼───┐
│ 所有机器自动信任 CA! │
│ • 浏览器:✅ https://app.localhost.dev │
│ • curl: ✅ curl https://api.localhost.dev │
│ • Python:✅ requests.get(https://...) │
│ • Node: ✅ fetch(https://...) │
└──────────────────────────────────────────────────┘
时序图:首次设置
开发者 cert-ctrl 代理 操作系统
服务器 (Windows) 信任存储
│ │ │ │
│ 1. 启动 │ │ │
│──────────────>│ │ │
│ │ │ │
│ 2. 安装代理 │ │
│──────────────────────────────>│ │
│ │ │ │
│ │ 3. 注册 │ │
│ │<───────────────│ │
│ │ │ │
│ │ 4. 发送 CA │ │
│ │────────────────>│ │
│ │ │ │
│ │ │ 5. 安装 CA │
│ │ │───────────────>│
│ │ │ │
│ │ │ 6. CA 受信任 │
│ │ │<───────────────│
│ │ │ │
│ │ 7. 确认成功 │ │
│ │<───────────────│ │
│ │ │ │
│ 8. 浏览 https://app.localhost.dev ✅ │
│────────────────────────────────────────────────>│
使用场景 2:生产证书分发
问题:手动证书部署
从 Let's Encrypt 获取证书
↓
😫 每 90 天,在每台服务器上:
↓
┌──────────────────────────────┐
│ ssh server1.example.com │
│ sudo certbot renew │
│ sudo cp cert to nginx │
│ sudo nginx -s reload │
│ │
│ ssh server2.example.com │
│ sudo certbot renew │
│ ... 重复 ... │
│ │
│ ssh server10.example.com │
│ ... 筋疲力尽 ... │
└──────────────────────────────┘
↓
忘记一台服务器?网站宕机!💥
解决方案:集中式证书管理
┌────────────────────────────────────────────┐
│ cert-ctrl 服务器 │
│ 1. 与 Let's Encrypt/ZeroSSL 通信 │
│ 2. 自动解决 DNS-01 挑战 │
│ 3. 存储证书 + 私钥(加密) │
│ 4. 跟踪到期,自动续期 │
└────────┬───────────────────────────────────┘
│
│ 代理轮询更新
│
├─────────┬─────────┬─────────┬─────────┐
▼ ▼ ▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ Web1 │ │ Web2 │ │ API │ │ LB │ │ CDN │
│ Nginx │ │ Nginx │ │Node.js││HAProxy│ │ 源站 │
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
│ │ │ │ │
└─────────┴─────────┴─────────┴─────────┘
所有服务器自动获取证书!✅
时序图:证书续期流程
cert-ctrl Let's Encrypt Cloudflare 代理(Web1) 代理(Web2)
服务器 API DNS
│ │ │ │ │
│ 1. 检查到期(第60天) │ │ │
│────────────────>│ │ │ │
│ │ │ │ │
│ 2. 请求新证书 │ │ │
│────────────────>│ │ │ │
│ │ │ │ │
│ │ 3. DNS 挑战 │ │
│ │───────────────>│ │ │
│ │ │ │ │
│ 4. 设置 TXT 记录 │ │ │
│────────────────────────────────>│ │ │
│ │ │ │ │
│ │ 5. 验证 │ │ │
│ │<──────────────>│ │ │
│ │ │ │ │
│ 6. 颁发证书 │ │ │ │
│<───────────────│ │ │ │
│ │ │ │ │
│ 7. 存储并加密证书 │ │ │
│ │ │ │ │
│ │ │ 8. 轮询更新 │
│ │ │<────────────│ │
│ │ │ │ │
│ 9. 新证书可用 │ │ │
│────────────────────────────────>│ │ │
│ │ │ │ │
│ │ │ 10. 部署并重载 │
│ │ │─────────────>nginx │
│ │ │ ✅ │
│ │ │ │ │
│ │ │ │ 11. 轮询 │
│ │ │ │<────────────│
│ │ │ │ │
│ 12. 新证书可用 │ │ │
│────────────────────────────────────────────────────────────>│
│ │ │ │ │
│ │ │ │ 13. 部署 │
│ │ │ │─────────────>nginx
│ │ │ │ ✅
时间线:90 天证书生命周期
第 0 天 │ 证书颁发(有效期 90 天)
│ ✅ cert.example.com(第 90 天到期)
│
第 30 天 │ 首次续期检查
│ ℹ️ 仍然有效,无操作
│
第 60 天 │ 触发自动续期
│ 🔄 cert-ctrl 联系 Let's Encrypt
│ 🔄 自动解决 DNS 挑战
│ ✅ 颁发新证书(有效期至第 150 天)
│ 🚀 代理部署到所有服务器
│ 🔄 Nginx/Apache 重新加载(零停机)
│
第 90 天 │ 旧证书过期
│ ✅ 已经替换!没人注意到!
│
第 120 天│ 下次续期检查
│ 🔄 重复循环...
对比表格
| 方面 | 手动管理 | cert-ctrl |
|---|---|---|
| 初始设置 | 每个域名 2-3 小时 | 15 分钟(一次性) |
| 续期 | 每 90 天 1-2 小时 | 自动(0 小时) |
| 停机时间 | 每次续期 5-30 分钟 | 零停机 |
| 错误率 | 高(人为错误) | 接近零(自动化) |
| 可扩展性 | 差(线性工作量) | 优秀(恒定工作量) |
| 多服务器 | 手动复制到每台 | 自动分发 |
| 监控 | 手动日历 | 内置警报 |
| 安全性 | 磁盘上未加密密钥 | 使用设备密钥加密 |
| 审计跟踪 | 无 | 完整审计日志 |
安全架构:设备特定加密
私钥如何保持安全
┌─────────────────────────────────────────────────────┐
│ cert-ctrl 服务器 │
│ │
│ 1. 证书颁发 │
│ 私钥:────────┐ │
│ ▼ │
│ 2. 使用主密钥包装(AES-256) │
│ 加密 Blob:[XXXXXXXXX] │
│ │ │
│ 3. 分配给设备 │ │
│ ▼ │
│ 4. 使用设备公钥包装(X25519) │
│ 设备特定 Blob:[YYYYYYYYY] │
└──────────────────────────┬──────────────────────────┘
│
│ 通过 HTTPS
▼
┌─────────────────┐
│ 代理 (Web1) │
│ │
│ 拥有:设备 │
│ 私钥 │
│ │ │
│ ▼ │
│ 解密 blob │
│ │ │
│ ▼ │
│ 私钥 │
│ (仅在内存中!)│
│ │ │
│ ▼ │
│ 安装到 │
│ /etc/nginx/ssl/│
└─────────────────┘
❌ Web2 的代理无法解密 Web1 的 blob
✅ 每个设备都有唯一的加密密钥
✅ 服务器从不存储未加密的私钥
✅ 私钥仅在安装期间存在于内存中
代理轮询机制
长轮询实现实时更新
代理 cert-ctrl 服务器
│ │
│ 1. 轮询(长超时:60秒) │
│─────────────────────────────────────>│
│ │
│ ... 连接保持打开 ... │
│ │
│ │ 2. 颁发新证书
│ │ (第60天自动续期)
│ │
│ 3. 响应:"新证书可用" │
│<─────────────────────────────────────│
│ │
│ 4. 获取证书 │
│─────────────────────────────────────>│
│ │
│ 5. 加密的证书包 │
│<─────────────────────────────────────│
│ │
│ 6. 解密并安装 │
│ 7. 重新加载 nginx │
│ │
│ 8. 再次轮询 │
│─────────────────────────────────────>│
│ ... 连接保持打开 ... │
相对于 webhooks 的优势:
- 无需配置防火墙
- 可在 NAT/代理后工作
- 代理发起连接(安全)
- 失败时自动重试
多云部署示例
┌────────────────────┐
│ cert-ctrl 服务器 │
│ (您的基础设施) │
└─────────┬──────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ AWS │ │ GCP │ │ Azure │
│ │ │ │ │ │
│ EC2 (Nginx) │ │ GCE (Node) │ │ VM (IIS) │
│ 代理 ✅ │ │ 代理 ✅ │ │ 代理 ✅ │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└─────────────────┼─────────────────┘
│
所有服务器使用同一证书!
每 60 天自动续期
这之所以可行是因为:
- 代理拉取证书(仅出站,无需打开防火墙)
- 同一证书可以部署到任何提供商
- 设备特定加密保护密钥安全
- 无供应商锁定
开发与生产工作流
开发工作流
┌──────────────────────────────────────────────────┐
│ 步骤 1:启动本地 cert-ctrl 服务器 │
│ docker-compose up │
│ 服务器自动生成自签名 CA │
└──────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 步骤 2:在开发机器上安装代理 │
│ certctrl-agent install --server localhost:8443│
│ 代理在系统中信任 CA │
└──────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 步骤 3:请求开发证书 │
│ 面板 → 新证书 │
│ 域名:myapp.localhost.dev │
│ 类型:自签名(CA) │
└──────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 步骤 4:在您的应用中使用 │
│ nginx 配置: │
│ ssl_certificate /var/certctrl/cert.pem; │
│ ssl_certificate_key /var/certctrl/key.pem; │
│ │
│ 浏览:https://myapp.localhost.dev ✅ │
└──────────────────────────────────────────────────┘
生产工作流
┌──────────────────────────────────────────────────┐
│ 步骤 1:将 cert-ctrl 部署到生产服务器 │
│ Kubernetes / Docker / VM │
│ 配置 DNS 提供商凭据 │
└──────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 步骤 2:请求公共证书 │
│ 面板 → 新证书 │
│ 域名:example.com │
│ DNS:Cloudflare(API 令牌) │
│ CA:Let's Encrypt(生产) │
└──────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 步骤 3:在生产服务器上安装代理 │
│ ssh web1 && certctrl-agent install │
│ ssh web2 && certctrl-agent install │
│ ssh api1 && certctrl-agent install │
└──────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 步骤 4:将证书分配给设备 │
│ 面板 → 分配 │
│ ☑ web1, web2, api1 │
│ 代理自动部署并重新加载 │
└──────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 步骤 5:然后就不用管了! │
│ • 第 60 天自动续期 │
│ • 零停机部署 │
│ • 出现问题时发送邮件警报 │
└──────────────────────────────────────────────────┘
这些图表展示了两种使用场景的完整工作流程,使用户能够轻松理解 cert-ctrl 如何简化开发和生产环境中的证书管理。