CMS 同步与证书运维
1. 概述
DAT CMS(Certificate Management Service)是负责生成并分发整个集群共享的证书的服务器。
各应用通过 CMS 客户端(DatCmsManager)定期获取证书列表,而这种同步将密钥轮换自动化。即使运维人员不亲自更换密钥,证书也会按既定周期重新生成,旧证书则会自行过期。
只有登录服务器会拿到可用于签发的证书,内容服务器只拿到仅供验证的证书。内容服务器只需知道 CMS,无需知道登录服务器。
2. 同步协议
2.1. 请求与响应
| 端点 | 用途 |
|---|---|
GET /v1/certs?version=N | 完整证书(含签名私钥) |
GET /v1/certs/verify-only?version=N | 仅验证用证书 |
GET /v1/certs.json、/v1/certs/verify-only.json | 相同内容的 JSON 格式 |
POST /v1/cert/{sig-alg}/{crypto-alg}/{delay}/{duration}/{ttl} | 手动生成证书(需要 Master 令牌) |
GET /health | 健康检查 |
响应正文是纯文本,第一行是服务器当前的 version,从第二行开始每行放一张证书。
1712345678
1a.1712345000.3600.1800.ECDSA-P256.IV-AES256-GCM.<sig-key>.<crypto-key>
2b.1712348600.3600.1800.ECDSA-P256.IV-AES256-GCM.<sig-key>.<crypto-key>2.2. 版本游标
客户端会记住最后一次成功的 version,并在下一次请求时带上它。服务器只挑选比该值更新的证书返回。
- 客户端的 version 比服务器旧时 → 只返回此后新生成的证书。
- 客户端的 version 比服务器新时(服务器更换、数据库初始化等)→ 将游标回退为
0,返回全量集合。 - 客户端只有在导入成功的情况下才推进 version。这是为了避免游标因失败的响应而前移,导致永久性地漏掉某些证书。
虽然是增量请求,但响应是全量替换
?version=N 是“请给我 N 之后的变更”的请求,但客户端会把收到的列表替换掉原有列表,而不是与之合并(clear = true)。这是因为服务器始终会判断出全部有效的证书并下发;正因如此,在 CMS 中被吊销(revoke)的证书不会残留在客户端。
2.3. 认证令牌
CMS 通过三种令牌来划分访问权限。
| 令牌 | 权限 |
|---|---|
Master令牌 | 生成DAT证书、查看服务器版本 |
Full Cert令牌 | 获取 Full (Pair Key, Hash Key) 证书 |
Verify Cert令牌 | 获取 Verify (Verify Key Only) 证书 |
原则上,对只做验证的服务器只发放 Verify Cert 令牌。不过加密密钥同样包含在 verify-only 响应中,因此关于其含义,请一并确认 证书 文档中的注意事项。
3. 证书签发延迟 (delay)
如果新证书一生成就立即用于签发,那么尚未完成同步的其他节点将无法验证由该证书签名的令牌。签发延迟正是为了消除这一区间而设置的值。
举例来说,假设 CMS 生成了证书 A,而服务器 1 和服务器 2 以 60 秒的周期进行同步。如果服务器 1 先取到并用 A 签发了 DAT,而服务器 2 尚未取到,那么服务器 2 就无法验证该 DAT。
如果把延迟设为 180 秒,那么证书生成后的 180 秒内将保持不可签发状态,在这段时间里所有服务器都能安全地完成同步。考虑到临时性的网络故障,建议将其设置为至少是各服务器同步周期的 3~4 倍以上。
4. 有意为之的行为
以下这些行为全都是设计上有意为之的,并不是缺陷。由于在运维时可能看起来与预期不符,故在此明确说明。
4.1. 签发窗口关闭之后仍会继续用缓存的证书签名
应用会持续使用在同步时刻选定的签发用证书,而不会在每次签发时重新检查 issuable()。
理由: 如果在与 CMS 断开连接的状态下签发窗口关闭,那么在“每次重新检查”的方式下,那一瞬间整个服务的登录都会停摆。DAT 在这种情况下选择了“即使没能取到新证书,也先继续签发”。
代价: 网络故障持续较久时,可能会继续用已经过了签发窗口的证书发出令牌。不过这些令牌在证书最终过期之前仍能在其他节点上正常通过验证,因此这被判断为一种优于“故障时服务直接挂掉”的权衡取舍。
4.2. 使用相同 CID 更新的证书会被丢弃
如果收到的证书与已持有证书的 CID 相同,则忽略新收到的那一份。
理由: CID 是证书的不可变标识符。如果同一个 CID 指向不同的密钥,那么已经签发并在流通中的令牌就无从判断应该用哪把密钥来验证。
更换密钥必须使用新的 CID
如果保持同一个 CID 只更换密钥再分发,那么它永远不会反映到客户端,而且也不会报错。 更换密钥时,请签发使用新 CID 的证书。
4.3. 没有新证书时会保留现有列表
如果响应中一张证书都没有,客户端会原样保留已持有的列表,而不会清空它。
理由: 在证书服务器宕机或响应异常这种最糟糕的时刻清空已持有的证书,会导致那一瞬间所有令牌验证全部失败。既然没有收到新的,那就用手上已有的撑住,这样更安全。
4.4. SINGLE_NODE 模式每次启动都会生成证书
以单节点模式运行 CMS 时,无论是否已存在可签发的证书,每次启动都会生成一张证书。
理由: 单节点模式是为了在没有额外基础设施的情况下独立运行 CMS 的配置。启动之后必须立刻就有可以签发的证书。
注意: 如果反复重启,证书会不断堆积。不过每张证书在超过自身的过期时刻后就会从列表中剔除,因此不会无限增长。
4.5. 没有可签发证书时会跳过延迟立即签发
在生成证书的时刻,如果一张可签发的证书都没有,CMS 会跳过延迟区间,并把延迟时间并入签发期限之中。
理由: 如果坚持保留延迟,那么在这段时间里整个集群一张令牌都签发不出来。在首次启动或全面故障恢复的场景下,必须能够立即签发。此时服务器日志中会留下一条警告。
5. 证书的回收与过期
- 证书会一直保留在分发列表中,直到最终过期(
start + duration + ttl)时刻为止。并不会因为签发窗口关闭就立刻消失。 - 在签发窗口结束前夕发出的 DAT 还会再存活自己的 TTL,因此即使是在那之后才首次启动的验证服务器,也能取到证书并验证该令牌。
- 超过最终过期时刻的证书会从列表中剔除,并在之后的清理作业中从存储中移除。
6. 部署
CMS 服务器的运行选项,以及 Docker · Kubernetes · 二进制部署方式和环境变量,在单独的文档中说明。