I
Editorial
证书过期是互联网服务里最常见、也最“丢人”的事故之一:系统一切正常,只是某个证书到期了,浏览器整页报错,API 客户端全部握手失败。随着证书有效期越来越短,手工管理越来越不可行。本帖整理一套预防思路。
一、为什么证书过期总会发生
1. 证书分散:主站、API 网关、CDN、负载均衡、内部服务、邮件服务器、VPN,各处各管。
2. 续期是低频操作:一年一次的事,经手人可能已经调岗。
3. 自动续期“静默失败”:续期脚本跑了,但因为 DNS 校验失败、80 端口被占、权限变化等原因没成功,没人收到通知。
4. 续期成功但没生效:新证书写到了磁盘,服务没有 reload,内存里还是旧证书。
二、第一步:建立证书清单
1. 列出所有对外和对内使用 TLS 的端点(域名 + 端口),包括非 443 端口,例如 SMTP 的 465/587、IMAP 993、数据库 TLS 端口。
2. 记录每个证书的签发方式(ACME 自动、手工购买)、部署位置、负责人和续期方式。
3. 证书透明度(CT)日志可以帮助发现遗漏:用 crt.sh 等公开查询服务搜索自己的域名,能看到所有已签发证书,常能找出被遗忘的子域名证书。
三、自动续期的要点
1. 优先使用 ACME 协议自动签发和续期(Let's Encrypt 等 CA 支持),客户端如 certbot、acme.sh、Caddy 内置、cert-manager(Kubernetes)。
2. 提前续期:通常在剩余有效期约三分之一时开始尝试,给失败重试留出时间。
3. 续期后自动 reload:certbot 可用 --deploy-hook,cert-manager 配合 Ingress 控制器会自动加载。务必验证“新证书真的被服务加载了”,而不只是文件更新了。
4. 校验方式选择:HTTP-01 需要 80 端口可达;DNS-01 适合通配符证书和内网服务,但要妥善保管 DNS API 凭据,权限尽量收窄到只能改 _acme-challenge 记录。
5. 续期失败要告警:把续期任务的退出码和日志接入监控,失败立即通知,而不是等到证书真的过期。
四、监控:从外部看真实结果
最可靠的监控是像客户端一样去连:
1. 定期对每个端点做 TLS 握手,读取实际下发证书的到期时间,例如:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -enddate
注意一定要带 -servername(SNI),否则多证书的服务器可能返回默认证书,结果不准。
2. Prometheus 体系可以用 blackbox_exporter 的 probe_ssl_earliest_cert_expiry 指标,设置剩余 21 天预警、7 天严重告警之类的分级阈值。
3. 多节点部署时,要对每个后端节点分别检查,避免负载均衡后面某一台没更新。
五、证书链问题
证书没过期但部分客户端报错,常见原因是证书链不完整:服务器只发了叶子证书,没发中间证书。浏览器有时能自动补全,但很多 API 客户端、老版本系统、嵌入式设备不会。
1. 部署时使用 fullchain(叶子 + 中间证书),不要只用 cert。
2. 用 openssl s_client -showcerts 查看服务器实际发送了几张证书。
3. 关注 CA 根证书和中间证书的更替公告,老设备信任库不更新时可能出现兼容问题,需要提前评估。
六、几条组织层面的建议
1. 证书负责人写进服务清单,交接时一并交接。
2. 手工购买的证书设置日历提醒,提醒对象是一个群组而不是个人。
3. 每季度做一次证书清单核对和过期演练:在测试环境故意部署一张快过期的证书,看告警是否按预期触发。
4. 私钥管理:私钥文件权限收紧,不要提交到代码仓库;怀疑泄露时立即吊销并重新签发。
大家有没有遇到过“证书已经续期了但服务还在用旧证书”的情况?是怎么发现和解决的?
一、为什么证书过期总会发生
1. 证书分散:主站、API 网关、CDN、负载均衡、内部服务、邮件服务器、VPN,各处各管。
2. 续期是低频操作:一年一次的事,经手人可能已经调岗。
3. 自动续期“静默失败”:续期脚本跑了,但因为 DNS 校验失败、80 端口被占、权限变化等原因没成功,没人收到通知。
4. 续期成功但没生效:新证书写到了磁盘,服务没有 reload,内存里还是旧证书。
二、第一步:建立证书清单
1. 列出所有对外和对内使用 TLS 的端点(域名 + 端口),包括非 443 端口,例如 SMTP 的 465/587、IMAP 993、数据库 TLS 端口。
2. 记录每个证书的签发方式(ACME 自动、手工购买)、部署位置、负责人和续期方式。
3. 证书透明度(CT)日志可以帮助发现遗漏:用 crt.sh 等公开查询服务搜索自己的域名,能看到所有已签发证书,常能找出被遗忘的子域名证书。
三、自动续期的要点
1. 优先使用 ACME 协议自动签发和续期(Let's Encrypt 等 CA 支持),客户端如 certbot、acme.sh、Caddy 内置、cert-manager(Kubernetes)。
2. 提前续期:通常在剩余有效期约三分之一时开始尝试,给失败重试留出时间。
3. 续期后自动 reload:certbot 可用 --deploy-hook,cert-manager 配合 Ingress 控制器会自动加载。务必验证“新证书真的被服务加载了”,而不只是文件更新了。
4. 校验方式选择:HTTP-01 需要 80 端口可达;DNS-01 适合通配符证书和内网服务,但要妥善保管 DNS API 凭据,权限尽量收窄到只能改 _acme-challenge 记录。
5. 续期失败要告警:把续期任务的退出码和日志接入监控,失败立即通知,而不是等到证书真的过期。
四、监控:从外部看真实结果
最可靠的监控是像客户端一样去连:
1. 定期对每个端点做 TLS 握手,读取实际下发证书的到期时间,例如:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -enddate
注意一定要带 -servername(SNI),否则多证书的服务器可能返回默认证书,结果不准。
2. Prometheus 体系可以用 blackbox_exporter 的 probe_ssl_earliest_cert_expiry 指标,设置剩余 21 天预警、7 天严重告警之类的分级阈值。
3. 多节点部署时,要对每个后端节点分别检查,避免负载均衡后面某一台没更新。
五、证书链问题
证书没过期但部分客户端报错,常见原因是证书链不完整:服务器只发了叶子证书,没发中间证书。浏览器有时能自动补全,但很多 API 客户端、老版本系统、嵌入式设备不会。
1. 部署时使用 fullchain(叶子 + 中间证书),不要只用 cert。
2. 用 openssl s_client -showcerts 查看服务器实际发送了几张证书。
3. 关注 CA 根证书和中间证书的更替公告,老设备信任库不更新时可能出现兼容问题,需要提前评估。
六、几条组织层面的建议
1. 证书负责人写进服务清单,交接时一并交接。
2. 手工购买的证书设置日历提醒,提醒对象是一个群组而不是个人。
3. 每季度做一次证书清单核对和过期演练:在测试环境故意部署一张快过期的证书,看告警是否按预期触发。
4. 私钥管理:私钥文件权限收紧,不要提交到代码仓库;怀疑泄露时立即吊销并重新签发。
大家有没有遇到过“证书已经续期了但服务还在用旧证书”的情况?是怎么发现和解决的?