深色模式
证书到期监控:提前告警防止过期中断
摘要:证书过期是典型的"完全可以避免却频繁发生"的故障。本文给出三种覆盖方式:本地文件扫描、远程端点探测、K8s Secret 扫描,并配一套分级告警规则。
适用环境
bash
cat /etc/os-release
openssl version
command -v blackbox_exporter && blackbox_exporter --version
command -v kubectl && kubectl version --short 2>/dev/null
command -v jq && jq --version1
2
3
4
5
2
3
4
5
操作步骤
1. 定义分级阈值
建议:剩余 30 天 warning、14 天 urgent、7 天 critical。同时监控"剩余天数"与"探测失败"两个维度。
2. 本地扫描:遍历证书文件计算剩余天数
bash
cat >/usr/local/bin/check-cert-files.sh <<'EOF'
#!/bin/bash
set -uo pipefail
WARN_DAYS=${WARN_DAYS:-30}
find /etc/letsencrypt/live /etc/ssl/certs -name "*.pem" -o -name "*.crt" 2>/dev/null | while read -r f; do
end=$(openssl x509 -in "$f" -noout -enddate 2>/dev/null | cut -d= -f2)
[ -z "$end" ] && continue
left=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))
cn=$(openssl x509 -in "$f" -noout -subject 2>/dev/null | sed 's/.*CN *= *//')
if [ "$left" -le "$WARN_DAYS" ]; then
echo "CERT_EXPIRING file=$f cn=$cn days_left=$left"
fi
done
EOF
chmod +x /usr/local/bin/check-cert-files.sh
/usr/local/bin/check-cert-files.sh1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3. 远程端点探测:blackbox_exporter + Prometheus
yaml
# blackbox.yml
modules:
http_2xx:
prober: http
timeout: 10s
http:
preferred_ip_protocol: ip41
2
3
4
5
6
7
2
3
4
5
6
7
yaml
# prometheus 抓取片段
scrape_configs:
- job_name: blackbox-https
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- https://example.com
- https://api.example.com
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:91151
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
告警规则:
yaml
groups:
- name: cert-expiry
rules:
- alert: CertificateExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 14 * 86400
for: 10m
labels: {severity: critical}
annotations:
summary: "证书即将过期: {{ $labels.instance }}"
- alert: CertificateExpiringWarning
expr: probe_ssl_earliest_cert_expiry - time() < 30 * 86400
for: 1h
labels: {severity: warning}
annotations:
summary: "证书 30 天内到期: {{ $labels.instance }}"
- alert: ProbeFailed
expr: probe_success == 0
for: 5m
labels: {severity: critical}
annotations:
summary: "HTTPS 探测失败: {{ $labels.instance }}"1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
4. K8s Secret 里的 TLS 证书扫描
bash
kubectl get secrets --all-namespaces -o json \
| jq -r '.items[] | select(.type=="kubernetes.io/tls")
| "\(.metadata.namespace) \(.metadata.name)"' \
| while read -r ns name; do
end=$(kubectl get secret "$name" -n "$ns" -o jsonpath='{.data.tls\.crt}' \
| base64 -d | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
[ -z "$end" ] && continue
left=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))
echo "ns=$ns secret=$name days_left=$left"
done1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
cert-manager 用户可直接看它维护的 Certificate 资源状态:
bash
kubectl get certificates --all-namespaces1
5. 用文本指标暴露给 node_exporter(无 Prometheus 时的轻量方案)
bash
cat >/etc/cron.daily/cert-expiry-report <<'EOF'
#!/bin/bash
/usr/local/bin/check-cert-files.sh > /var/log/cert-expiry.today
diff -q /var/log/cert-expiry.today /var/log/cert-expiry.last >/dev/null \
|| cat /var/log/cert-expiry.today | mail -s "[cert] 证书到期提醒 $(hostname)" ops@example.com
cp /var/log/cert-expiry.today /var/log/cert-expiry.last
EOF
chmod +x /etc/cron.daily/cert-expiry-report1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
6. 告警之外:把续期也自动化
监控只负责"兜底",主路径仍是自动续期。两者都要有:续期失败时监控是最后一道防线。
验证
bash
# 用一张 1 天有效期的测试证书验证告警链路
openssl req -x509 -newkey rsa:2048 -nodes -days 1 \
-subj "/CN=expire-test.local" \
-keyout /tmp/t.key -out /etc/ssl/certs/expire-test.crt
WARN_DAYS=30 /usr/local/bin/check-cert-files.sh # 应输出 CERT_EXPIRING
rm -f /etc/ssl/certs/expire-test.crt /tmp/t.key
curl -s 'http://127.0.0.1:9090/api/v1/rules' | jq '.data.groups[].rules[].name' 2>/dev/null1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
判定标准:测试证书触发告警;真实证书剩余天数可视化;告警能到人(电话/IM)。
常见坑
只监控公网域名,漏掉内网自签证书
内网证书因无外部提醒最易过期。务必把 /etc/ssl/certs 与 K8s Secret 一起纳入。
探针只看 HTTP 200,不看证书时间
probe_success=1 不代表证书没快过期。必须单独用 probe_ssl_earliest_cert_expiry 做阈值告警。
告警发到没人看的邮件列表
到期告警必须有明确值班人与升级路径。建议同时接入 IM 与电话,并做一次真实演练。
SNI 场景下探测结果不一致
同一 IP 多域名时必须带 -servername,否则拿到的是默认站点证书。blackbox 用完整 URL 即可正确带 SNI。
时钟漂移导致剩余天数计算错误
计算依赖本机时间。确保 NTP/chrony 正常:chronyc tracking。