还有好几个月才到期的证书,与立刻失败的登录,指向两个不同时钟上的不同对象。服务器拒绝连接,是因为它查询的已吊销证书列表已经超过了自己的到期时间,而不是用户的证书过期了。续期用户证书对那份列表毫无帮助。

把这两条时间线分开,就是全部诊断;它也决定了修复应该是什么样子。

两个时钟,只有一个是证书

证书带有有效期窗口。证书吊销列表带有自己的窗口,还带有签发者和签名;只要列表的下次更新时间已过,验证方就拒绝信任它。发生这种情况时,客户端出示的证书完全有效,服务器却仍然断开连接,并给出一条关于列表的消息。用户把这条消息读成“证书过期了”,于是把续期请求送到了错误的地方。

这两个对象的所有者也不同:证书来自签发它的 CA,而列表由运营该 CA 的人按计划生成。用户无法刷新它,重新签发证书也无法延长它。

读服务实际加载的那份列表

从正在运行的配置出发,而不是从你预期的文件出发。crl-verify 的路径可能是绝对路径、相对于配置文件的路径,也可能是烤进镜像里的副本,而验证方读的正是那份副本。用 openssl crl -in /etc/openvpn/crl.pem -noout -issuer -lastupdate -nextupdate 就地检查它,并把日期与服务器的时钟对照。

然后确认这个文件确实是在用的那一个:用 openssl crl -in /etc/openvpn/crl.pem -CAfile /etc/openvpn/ca.crt -noout 检查它的签名,该命令报告验证结果,而不是默默打印字段。由另一个 CA 签名的列表,或者留在第二个目录里的旧副本,失败起来和过期列表一模一样。

从吊销数据库重新生成,而不是从零开始

新列表必须来自 CA 当前的吊销数据库,并经过批准的签名流程。生成空列表,或从索引的旧备份重新生成,会悄悄撤销自那次备份以来加入的每个身份的吊销状态。这把一次登录中断变成了安全回退,而没人察觉,因为症状消失了。

把生成步骤和其余 CA 工具一起放进版本控制,让间隔和签名密钥有据可查,而不是靠记忆。运行手册里有一条写明命令、签名者和发布目标的记录就够了。这样任何值班的人都能重新生成,而不必猜哪个索引文件才是权威的。把列表的序号和下次更新时间连同部署记录一起保存。

部署到验证方读取的位置

把新列表复制到服务读取的路径,设置所有者和权限模式,让服务账户能读而其他人不能,然后按文档所述的行为重新加载或重启。如果守护进程在启动时缓存列表,只替换文件而不重新加载,运行中的进程什么都不会察觉。重新加载后,确认进程报告的时间戳。

如果有多项服务在验证客户端,就部署到每一个。只更新一个端点而让另一个保留旧副本,产生的故障只会出现在落到第二个端点的用户身上。把这份端点的短名单记在同一本运行手册里。上线后,逐个检查它们报告的列表日期,而不是假设副本已经就位。

在下一个截止时间到来之前让它可见

更长的发布间隔能降低这类事件的发生频率,但不会建立起流程。按运营方的策略选定间隔,然后针对已部署列表的下次更新时间字段设置告警,并留出足够的前置时间重新生成和部署。要对已部署的那份副本告警,而不是对 CA 主机告警,因为失败的是已部署的副本。

部署之后,两个方向都要验证:被允许的用户能连上,已知被吊销的身份仍然失败。第二项检查才能抓住不完整的重新生成,它只需要用一条命令,针对你专门为此保留的测试配置运行。

相关文章