前言
在現代 IT 基礎設施中,SSL/TLS 憑證是確保通訊安全的關鍵元件。然而,憑證過期往往是造成服務中斷的常見原因之一。本文將介紹如何建立一套完整的憑證過期監控與告警系統,確保您的服務不會因為憑證過期而中斷。
憑證監控的重要性
為什麼需要監控憑證?
- 避免服務中斷:憑證過期會導致 HTTPS 連線失敗,用戶將看到安全警告
- 維護品牌信譽:憑證錯誤會降低用戶對網站的信任度
- 合規要求:許多產業法規要求持續維護有效的加密憑證
- 自動化管理:隨著微服務架構普及,手動追蹤數百個憑證已不切實際
常見的憑證問題
- 憑證已過期
- 憑證即將過期(通常 30 天內需要關注)
- 憑證鏈不完整
- 憑證與網域名稱不符
使用 OpenSSL 檢查憑證到期日
基本指令
檢查遠端伺服器憑證:
1
2
3
4
5
6
7
| # 檢查網站憑證到期日
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
# 輸出範例:
# notBefore=Jan 1 00:00:00 2024 GMT
# notAfter=Dec 31 23:59:59 2024 GMT
|
計算剩餘天數
1
2
3
4
5
6
7
8
9
| # 取得憑證到期日並計算剩餘天數
DOMAIN="example.com"
EXPIRY_DATE=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))
echo "憑證將在 $DAYS_LEFT 天後過期"
|
批次檢查腳本
以下腳本可以批次檢查多個網域的憑證狀態:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
| #!/bin/bash
# cert_check.sh - 批次憑證檢查腳本
# 設定告警閾值(天數)
WARNING_DAYS=30
CRITICAL_DAYS=7
# 要檢查的網域清單
DOMAINS=(
"example.com"
"api.example.com"
"admin.example.com"
"www.example.com"
)
# 顏色定義
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
check_certificate() {
local domain=$1
local port=${2:-443}
# 取得憑證到期日
expiry_date=$(echo | openssl s_client -servername "$domain" \
-connect "$domain:$port" 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -z "$expiry_date" ]; then
echo -e "${RED}[ERROR]${NC} $domain - 無法取得憑證資訊"
return 1
fi
# 計算剩餘天數
expiry_epoch=$(date -d "$expiry_date" +%s)
current_epoch=$(date +%s)
days_left=$(( ($expiry_epoch - $current_epoch) / 86400 ))
# 根據剩餘天數顯示不同狀態
if [ $days_left -lt $CRITICAL_DAYS ]; then
echo -e "${RED}[CRITICAL]${NC} $domain - 剩餘 $days_left 天 (到期: $expiry_date)"
elif [ $days_left -lt $WARNING_DAYS ]; then
echo -e "${YELLOW}[WARNING]${NC} $domain - 剩餘 $days_left 天 (到期: $expiry_date)"
else
echo -e "${GREEN}[OK]${NC} $domain - 剩餘 $days_left 天 (到期: $expiry_date)"
fi
}
echo "=========================================="
echo "憑證到期檢查報告 - $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="
for domain in "${DOMAINS[@]}"; do
check_certificate "$domain"
done
|
Prometheus 與 ssl_exporter
安裝 ssl_exporter
ssl_exporter 是專門用於監控 SSL 憑證的 Prometheus exporter。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| # 下載並安裝 ssl_exporter
wget https://github.com/ribbybibby/ssl_exporter/releases/download/v2.4.2/ssl_exporter-2.4.2.linux-amd64.tar.gz
tar xvzf ssl_exporter-2.4.2.linux-amd64.tar.gz
sudo mv ssl_exporter-2.4.2.linux-amd64/ssl_exporter /usr/local/bin/
# 建立 systemd 服務
sudo tee /etc/systemd/system/ssl_exporter.service > /dev/null <<EOF
[Unit]
Description=SSL Certificate Exporter
After=network.target
[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/bin/ssl_exporter
Restart=always
[Install]
WantedBy=multi-user.target
EOF
# 啟動服務
sudo systemctl daemon-reload
sudo systemctl enable ssl_exporter
sudo systemctl start ssl_exporter
|
Prometheus 設定
在 prometheus.yml 中加入以下設定:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| scrape_configs:
- job_name: 'ssl'
metrics_path: /probe
static_configs:
- targets:
- example.com:443
- api.example.com:443
- admin.example.com:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9219 # ssl_exporter 位址
|
重要的監控指標
ssl_exporter 提供以下關鍵指標:
ssl_cert_not_after - 憑證到期時間戳記ssl_cert_not_before - 憑證生效時間戳記ssl_verified_cert_not_after - 已驗證憑證鏈的到期時間
Grafana 儀表板
建立憑證監控儀表板
以下是 Grafana 儀表板的 JSON 設定片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| {
"panels": [
{
"title": "憑證剩餘天數",
"type": "gauge",
"targets": [
{
"expr": "(ssl_cert_not_after - time()) / 86400",
"legendFormat": "{{instance}}"
}
],
"fieldConfig": {
"defaults": {
"thresholds": {
"steps": [
{ "value": 0, "color": "red" },
{ "value": 7, "color": "orange" },
{ "value": 30, "color": "yellow" },
{ "value": 60, "color": "green" }
]
},
"unit": "d"
}
}
}
]
}
|
常用 PromQL 查詢
1
2
3
4
5
6
7
8
| # 計算憑證剩餘天數
(ssl_cert_not_after - time()) / 86400
# 找出 30 天內即將過期的憑證
(ssl_cert_not_after - time()) / 86400 < 30
# 憑證到期時間表格
ssl_cert_not_after * 1000
|
AlertManager 告警設定
告警規則
建立 /etc/prometheus/rules/ssl_alerts.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| groups:
- name: ssl_certificate_alerts
rules:
- alert: SSLCertificateExpiringSoon
expr: (ssl_cert_not_after - time()) / 86400 < 30
for: 1h
labels:
severity: warning
annotations:
summary: "SSL 憑證即將過期"
description: "{{ $labels.instance }} 的憑證將在 {{ $value | printf \"%.0f\" }} 天內過期"
- alert: SSLCertificateCritical
expr: (ssl_cert_not_after - time()) / 86400 < 7
for: 1h
labels:
severity: critical
annotations:
summary: "SSL 憑證即將過期 - 緊急"
description: "{{ $labels.instance }} 的憑證將在 {{ $value | printf \"%.0f\" }} 天內過期,請立即處理!"
- alert: SSLCertificateExpired
expr: (ssl_cert_not_after - time()) < 0
for: 5m
labels:
severity: critical
annotations:
summary: "SSL 憑證已過期"
description: "{{ $labels.instance }} 的憑證已經過期!"
|
AlertManager 通知設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| # alertmanager.yml
global:
slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10m
repeat_interval: 1h
receiver: 'slack-notifications'
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
receivers:
- name: 'slack-notifications'
slack_configs:
- channel: '#alerts'
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'pagerduty-critical'
pagerduty_configs:
- service_key: YOUR_PAGERDUTY_KEY
|
雲端解決方案
AWS Certificate Manager (ACM)
ACM 提供自動續約功能,搭配 CloudWatch 進行監控:
1
2
3
4
5
6
7
| # 使用 AWS CLI 列出所有憑證
aws acm list-certificates --region ap-northeast-1
# 取得憑證詳細資訊
aws acm describe-certificate \
--certificate-arn arn:aws:acm:ap-northeast-1:123456789:certificate/xxx \
--query 'Certificate.NotAfter'
|
Azure Key Vault
1
2
3
4
5
6
7
8
| # 列出所有憑證
az keyvault certificate list --vault-name MyKeyVault
# 取得憑證到期日
az keyvault certificate show \
--vault-name MyKeyVault \
--name MyCertificate \
--query 'attributes.expires'
|
自動化續約整合
結合 Certbot 自動續約
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #!/bin/bash
# /etc/cron.weekly/cert-renew-check.sh
# 檢查並續約憑證
certbot renew --quiet
# 重新載入服務
systemctl reload nginx
# 發送通知
if [ $? -eq 0 ]; then
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"憑證續約檢查完成"}' \
https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
fi
|
使用 cert-manager (Kubernetes)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-tls
namespace: default
spec:
secretName: example-com-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- example.com
- www.example.com
renewBefore: 360h # 到期前 15 天續約
|
最佳實踐
監控策略建議
設定多層告警閾值
- 60 天:資訊通知
- 30 天:警告通知
- 7 天:緊急通知
- 已過期:立即通知 + 呼叫值班人員
建立憑證清單
- 維護所有憑證的集中清單
- 記錄憑證用途、負責人、到期日
自動化續約
- 盡可能使用自動續約機制
- 對於無法自動續約的憑證,提前安排更新時間
定期審查
- 每季度審查一次憑證狀態
- 移除不再使用的憑證
- 更新監控清單
監控檢查清單
參考資料
結語
建立完善的憑證監控系統是維護服務可用性的重要環節。透過本文介紹的工具和方法,您可以有效地監控所有憑證的狀態,並在問題發生前及時處理。建議從簡單的腳本開始,逐步導入 Prometheus 等完整的監控方案,最終實現憑證管理的完全自動化。