一次 HTTPS 证书过期事故复盘

Cold 发布于 2024-08-17 67 次阅读 700 字 预计阅读时间: 3 分钟 问题排查


周一早上九点,公司业务群被刷屏:官网打不开,浏览器满屏大红警告"您的连接不是私密连接"。看了一眼就明白了——SSL 证书过期,而且是整站所有域名一起过期。这次事故从发现到恢复 50 分钟,暴露的问题很典型,写个复盘。

事故经过

证书是 Let's Encrypt 的,服务器上配着 certbot 的 systemd timer 自动续签。按理说不可能过期。登录服务器查:

systemctl list-timers | grep certbot   # timer 在跑
certbot renew --dry-run               # 手动模拟续签

dry-run 报错了:验证失败。顺着报错查下去,原因是三个月前的一次安全加固,把防火墙里 80 端口对 Let's Encrypt 验证服务器的放行规则收紧了(当时只考虑了国内访问来源),HTTP-01 验证过不去,续签就一直失败。timer 每周跑、每周失败、失败通知发到了一个没人看的邮箱。三个月后证书到期,整站爆炸。

应急恢复:临时开 80 端口验证,手动 renew 成功,reload nginx,九点五十全站恢复。

暴露的三个问题

  • 续签依赖 HTTP-01 验证,而验证通道被变更破坏。任何对 80 端口、防火墙、Nginx location 的变更都可能杀死续签,但没有任何机制发现它
  • 失败告警进了死信箱。告警的价值取决于有人看它,没人看的告警等于没有
  • 没有独立的证书到期监控。续签机制自己失败了,没有任何一道独立防线在它之外兜底

整改措施

  • 验证方式换成 DNS-01,和 80 端口彻底解耦(用 DNS 插件自动加 TXT 记录,不再怕防火墙变更)
  • 证书到期独立监控:外部拨测(用的 Uptime Kuma 自建)每天检查所有域名证书剩余天数,小于 14 天告警到企业微信群。注意监控一定要"外部"的,续签流程内部再怎么自检都有共同的盲区
  • certbot 失败通知接到告警机器人,每周的续签结果进值班群可见
  • 变更 checklist 加一条:动 80/443 端口相关配置后,必须跑一次 certbot renew --dry-run

一点感想

这次事故的本质:自动化让你以为高枕无忧,于是撤掉了所有人工检查,但自动化本身也是会被变更破坏的基础设施。任何"一劳永逸"的机制都需要一个独立的监控在旁边盯着,否则它坏掉的那天就是你被打脸的那天。50 分钟的事故换来这堂课,不算贵。

和喜欢的一切在一起~
最后更新于 2024-08-17