改变身份的证书续订不是续订,而是披着维护工单外衣的迁移。客户端会校验名称、证书链,有时还会校验特定密钥,而这三者都可能在到期日不变的情况下改变。在申请替换之前,写下客户端实际检查的内容:主机名或对端身份、证书用途、密钥策略和签发链。续订是例行还是需要协调,取决于替换改变了其中哪一项。

三个条件决定续订的形态

这三个条件是:是否有东西固定了叶证书、证书链是否改变、还有谁在验证名称。要从客户端一侧回答,而不是图 CA 的方便,因为凌晨三点出故障的正是客户端。

从检查现有证书开始。openssl x509 -in server.crt -noout -subject -issuer -dates -ext subjectAltName 会打印主题、签发者、有效期窗口以及该证书实际有效的名称。最后一项最重要,也最常被想当然:续订请求若漏掉客户端依赖的 SAN,就会得到一张技术上有效、功能上错误的证书。请从旧证书复制 SAN 列表到请求中,不要凭记忆重新输入。

条件一:是否有东西固定了叶证书

如果客户端信任受维护的 CA 并校验名称,那么换用新密钥续订叶证书对它们是不可见的。只要有任何客户端固定了叶证书、其指纹或其公钥,替换就是需要硬切换的协调变更,因为旧的固定无法验证新证书。

先弄清自己属于哪种情况,再下任何订单。没有人记录过的固定,在失效时依然是固定。

条件二:比较固定项和证书链

指纹让固定项可以核查:在旧证书和新证书上运行 openssl x509 -noout -fingerprint -sha256 -in server.crt,并用 openssl x509 -noout -pubkey 比较公钥。如果客户端配置、移动配置文件或设备信任库中包含其中任一值,就说明存在固定。移动 VPN 配置文件是常见的藏身之处,因为配置文件只分发一次,之后再也不被检查。

如果替换来自同一个中间证书,而且客户端已经拥有或能够获取该中间证书,信任一侧就不会有任何变化。新的中间证书、不同的签发者,或以错误顺序下发的证书链,都会把续订变成信任变更,而故障看起来像未知签发者,而不是证书过期。

用 openssl s_client -connect vpn.example.com:443 -servername vpn.example.com -showcerts 检查服务器实际发送的证书链,并用 openssl verify -CAfile ca.pem -untrusted chain.pem server.crt 在本地验证它。在变更前做这件事,能为之后的比对提供基线。

条件三:还有谁在验证名称

VPN 集中器、负载均衡器、监控探针、RADIUS 或 SAML 集成以及移动配置文件,各自都可能保存着预期名称或信任锚的副本。续订正是这些副本出现分歧的时刻,因为证书变了,而副本没变。

在变更前列出所有使用方,并为每一个决定是否需要更新。你忘掉的那一个,就是会来叫醒你的那一个。

还有一个时间陷阱。既要检查有效期起点,也要检查到期时间,因为为稍后启用而准备的证书如果安装得太早会被拒绝,而错误看起来像时钟问题,而不是准备问题。部署前对新文件运行 openssl x509 -noout -dates 是两秒钟的检查。还要保留受支持的恢复路径和已知良好的配置,这样出错的续订可以通过恢复先前的证书和密钥来回滚。

部署,用全新认证验证,然后退役

已建立的隧道反映的是建立时所发生的验证,因此它看起来健康,而每条新连接都在失败。请用客户端实际使用的服务名做一次全新认证来测试。

完成用户真正关心的应用层检查,并从客户端而不是服务器的角度确认证书链的下发。不要为了保持切换安静而压制名称或证书检查;那会把临时的兼容性问题变成永久问题。

只有在推出经过验证之后才退役过时材料,并把泄露的密钥当作完全不同情况处理:仅靠续订不会吊销任何东西,因此受影响身份需要该部署的吊销和会话处理流程。RFC 5280 定义了这一切底层的证书与路径验证规则。把例行的叶证书续订与 CA 替换分开,这样客户端就不会被无故要求信任新的签发者。

相关文章