证书过期事故复盘:监控该怎么写才真的会响
证书过期是最"低级"却又最常见的线上事故之一,因为它有三个特点:过期时间是确定的、影响是全量的、而监控往往是缺失的。复盘过几次之后,我把证书监控拆成三条线。
一、不要只监控一个域名
事故里最常见的对话是"我们监控了主站啊"。真正会挂的是那些没人记得的域名:老版本的 API 域名、CDN 回源域名、给第三方回调用的域名、内部服务之间的 mTLS 证书。做法是从配置里反推:把所有 nginx 的 server_name、所有对外域名清单、所有 Kubernetes Ingress 的 host 抓出来,去重后统一纳入检查。
二、检查的是"链"而不是"证书"
只取叶子证书的 notAfter 是不够的。中间证书过期同样会失败,而很多服务器配置里中间证书是打包在 fullchain 里的,单独看叶子会漏。检查脚本应该解析整条链,对每一张证书算剩余天数:
```bash
echo | openssl s_client -servername "$h" -connect "$h:443" 2>/dev/null | openssl crl2pkcs7 -nocrl -certfile /dev/stdin | openssl pkcs7 -print_certs -noout
```
拿到每张证书后用 `openssl x509 -noout -enddate` 取到期时间,剩余天数小于阈值就报警。阈值建议双档:30 天告警(工作日处理得及),7 天严重告警(该拉群了)。
三、要监控"续期是否成功",而不只是"还有几天"
自动续期(certbot、ACME 客户端)才是根因高发区:磁盘满了、80 端口被占、DNS 验证失败、renew hook 没 reload nginx——这些都会导致"续了但没生效"。所以还要加两条检查:一是定时任务本身的成功率(续期脚本失败要报),二是证书指纹是否变化过(续期成功后应当变化,长期不变说明根本没续)。
四、把检查做成可跑的一行命令
监控最怕临时手搓。给团队一条能随时跑的命令,比什么都实用:
```bash
for h in api.example.com www.example.com cdn.example.com; do
d=$(echo | openssl s_client -servername "$h" -connect "$h:443" 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
echo "$h -> $d"
done
```
把它挂到定时任务里,输出落盘,超过阈值就推消息。写一次,后面每次加域名只需要往列表里加一行。
五、用一个真实的失败案例收尾
上个月一台机器上的证书在凌晨两点过期,事故报告里写着"监控没有覆盖"。查下来是三个原因叠加:监控清单里只有主域名,出问题的是给第三方回调用的子域名;检查脚本只看了叶子证书,那台机器上真正过期的是中间证书;告警发到了一个三个月没人看的邮箱。三个原因都不复杂,但没有一条属于"技术难题",全是流程漏洞。所以我们后来把这三件事固化成模板:域名清单从配置自动生成、链条逐张检查、告警必须发到有人的群。技术方案再漂亮,缺了执行纪律一样会挂。
最后补一句运维纪律:证书续期必须走自动化,但自动化的失败必须有人收到通知。任何"配置一次永不再看"的东西,都会在某天以事故的形式回来找你。
- 点赞
- 收藏
- 关注作者
评论(0)