VPN 证书尚未生效:三种原因,一种排查顺序
“尚未生效”意味着设备时钟落后、有效期确实开始得更晚,或中间证书尚未生效。请按这个顺序排查。
你打开客户端,选中用了几个月的配置文件,它却以“certificate is not yet valid”停下。你的登录信息没有任何变化,信任存储大概也没问题:握手中出示的证书带有一个有效期窗口,它的起点晚于验证方正在使用的那一刻。三种不同情形都会产生这条完全相同的消息,而它们需要不同的处理。下面的顺序能让你在动时钟或证书文件之前判断自己属于哪一种。
你面对的是三种原因中的哪一种
第一种原因是本地的:执行检查的设备所持时钟早于证书的起始日期。你会在 CMOS 电池耗尽的硬件上、从旧快照恢复的虚拟机上、断电足够久而丢掉时间的设备上,以及出站 NTP 被封锁却无人察觉的网络里看到它。证书可以完全有效,却仍然以这种方式失败。
第二种原因属于签发方,因为证书确实从未来才开始生效:签发过早、以显式起始时间生成,或作为尚未执行的激活步骤的一部分被签名。第三种原因最浪费时间,因为叶子证书是当前的,而所出示链条中的另一张证书不是,于是报错指向你从未安装过的材料。
一个问题能把它们分开。故障是跟着设备走,还是跟着服务走?同一网络里两台机器表现不同,指向时钟。每个客户端都以同样方式失败,指向证书的有效期窗口及其背后的链条。
从实际出示的那张证书读取有效期窗口
不要检查上一次部署遗留的 PEM 文件;向服务索取它此刻发送的链条。openssl s_client -connect vpn.example.com:443 -servername vpn.example.com -showcerts 会打印链条中的每一张证书。保存你关心的那段,运行 openssl x509 -noout -subject -issuer -dates;后者会打印 notBefore 和 notAfter,正是这两个值起决定作用。在 Windows 上,连接对应的证书对话框以及对导出文件运行 certutil -dump 会显示相同字段。
要读窗口的两端,而不只是起点。两小时后才生效的证书和两小时后过期的证书,报错不同,牵涉的团队也不同。记下报错点名的是哪一张证书——叶子、中间还是根——因为这决定了客户端这一侧到底有没有可修的东西。
你也可以不等它生效就测试。验证接受一个显式时间:openssl verify -attime 1793600000 -CAfile ca.pem -untrusted intermediate.pem leaf.pem 会按该时间戳评估链条。先用当前时间运行以复现故障,再用证书的起始时间运行,确认窗口一打开同一条链就能通过。RFC 5280 定义了有效期字段,以及证书不得在其之外使用的规则,这正是你的客户端刚刚执行的规则。
是你的时钟,还是他们的
把你信任的来源给出的证书起始时间与设备时钟按 UTC 比较。date -u 给出当前时刻,systemd 主机上的 timedatectl status 还会报告时钟是否已同步。在 Windows 上,w32tm /query /status 显示当前时间源和上次成功同步。任务栏里显示的时区只是显示选择,不是时钟错误;验证方比较的是 UTC 时刻。
| What you see | Most likely reading | Next step |
|---|---|---|
| Clock behind, one device affected | Local time fault | Resync time, keep validation on, retest |
| Clock correct, window opens soon | Certificate staged early | Wait for the window or follow the cutover plan |
| Clock correct, intermediate not yet valid | Chain material mismatch | Operator replaces the intermediate |
| Some peers pass, others do not | Inconsistent nodes | Record each peer's chain before changing anything |
如果时钟落后,先重新同步并重测,再改动任何证书材料。偏差几分钟或几小时的设备会拒绝它遇到的每一张新签发证书,而不只是某一个服务,所以“只是某个服务”的解释通常是错的。如果时钟正确且已同步,就别再盯着设备:窗口属于签发方,不该为了让它通过而调整任何本地设置。
那张表就是全部判断。把时钟挪到证书期望的位置不是修复,关掉时间检查也不是,因为两者都掩盖了产生错误的条件。
叶子看起来正常,链条为什么失败
续期的叶子和替换用的中间证书通常一起下发,但并不总在同一时刻落地。服务可能发送一张由中间证书签名的新叶子,而那张中间证书自身的窗口开始得更晚;也可能在新叶子之下继续提供较旧的中间证书。无论哪种,叶子自己的日期看着合理,链条却失败。
负载均衡的端点会把“坏掉”变成“不一致”。如果重试成功,或者一个网络能用而另一个不能,在改设置之前记下是哪个对端应答、发的是哪条链。openssl s_client 会打印连接到的地址,试几次就能看出每个节点是否提供同一条链。
保持验证完整的修复路径
时钟问题在设备上修,验证保持开启。证书问题由运营方用已覆盖当前时间的窗口所签发的材料来修。没有任何客户端设置能让尚未生效的证书变得有效;跳过时间检查的开关是用来确认诊断的,不是用来上生产的。
当证书是为计划中的激活而预备时,按切换计划执行。在窗口打开时安装,或使用提供方记录的叠替流程,而不是提前安装、再教用户点掉警告。人们学会忽略的警告,比一次短暂延迟代价更大。
最后,按故障发生的方式重测:新会话、同一客户端、你真正需要的资源。TLS 库可能在连接生命周期内缓存已验证的链条,恢复的会话未必再查一次,所以旧会话可能在修复后继续失败,或在回归后继续可用。能在查看器里打开文件,只证明文件可读;完成一次握手,才证明链条通过验证。
关单之前确认四件事:故障设备的 UTC 时间与同步状态、所出示链条中每张证书的 notBefore 与 notAfter、第二个客户端拿到的同一条链,以及报错点名的那张证书。如果时钟正确而窗口尚未打开,剩下的就是运营方的工作,你这边正确的做法是等窗口,而不是削弱检查。