17.10.5 Alertmanager与Webhook安全
Alertmanager 与 Webhook 安全需要同时关注告警数据完整性、传输机密性与接收端访问控制,避免伪造告警与通知风暴。
原理草图(告警流与安全控制点)#
安装与基础准备(示例环境)#
- Alertmanager 走 Nginx 反向代理,Nginx 终止 TLS 并做 Basic Auth。
- Webhook 接收端使用 Python/Flask,支持 HMAC 签名校验。
1) 安装 Nginx 与生成证书#
# Debian/Ubuntu
sudo apt update && sudo apt install -y nginx apache2-utils openssl
# 生成自签证书(实验环境)
sudo mkdir -p /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/alert.key \
-out /etc/nginx/ssl/alert.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Ops/OU=Sec/CN=alert.example.com"
2) 生成 Basic Auth 账号#
sudo htpasswd -c /etc/nginx/.htpasswd alertuser
# 输入密码,用于访问 Alertmanager UI/API
3) 配置 Nginx 反向代理#
/etc/nginx/conf.d/alertmanager.conf
server {
listen 443 ssl;
server_name alert.example.com;
ssl_certificate /etc/nginx/ssl/alert.crt;
ssl_certificate_key /etc/nginx/ssl/alert.key;
# 限流:每 IP 每秒 5 个请求,突发 10
limit_req_zone $binary_remote_addr zone=alert_zone:10m rate=5r/s;
location / {
limit_req zone=alert_zone burst=10 nodelay;
auth_basic "Alertmanager";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:9093;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
sudo nginx -t && sudo systemctl reload nginx
Alertmanager 侧安全配置示例#
/etc/alertmanager/alertmanager.yml
global:
resolve_timeout: 5m
route:
receiver: "webhook-secure"
receivers:
- name: "webhook-secure"
webhook_configs:
- url: "https://webhook.example.com/alert"
send_resolved: true
http_config:
tls_config:
insecure_skip_verify: false
authorization:
type: "Bearer"
credentials: "TOKEN_123456"
命令解释
- send_resolved: 告警恢复也会通知,便于接收端做清理。
- authorization: 在 Header 中注入 Authorization: Bearer TOKEN_123456。
Webhook 接收端示例(HMAC 签名校验)#
/opt/webhook/app.py
from flask import Flask, request, abort
import hmac, hashlib, json, time
app = Flask(__name__)
SECRET = b"WEBHOOK_SHARED_SECRET"
def verify_signature(raw_body, signature):
mac = hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(mac, signature)
@app.route("/alert", methods=["POST"])
def alert():
raw = request.get_data()
sig = request.headers.get("X-Signature", "")
token = request.headers.get("Authorization", "")
if token != "Bearer TOKEN_123456":
abort(401, "invalid token")
if not verify_signature(raw, sig):
abort(403, "invalid signature")
data = request.json
# 仅打印必要字段,避免敏感信息泄露
print(json.dumps({
"status": data.get("status"),
"receiver": data.get("receiver"),
"alerts": len(data.get("alerts", []))
}))
return "ok", 200
if __name__ == "__main__":
app.run(host="0.0.0.0", port=9001)
启动与依赖安装#
python3 -m venv /opt/webhook/venv
source /opt/webhook/venv/bin/activate
pip install flask
python /opt/webhook/app.py
发送测试告警(生成签名)#
BODY='{"status":"firing","receiver":"webhook-secure","alerts":[{"labels":{"alertname":"Test"}}]}'
SIG=$(python3 - <<'PY'
import hmac,hashlib
body=b'''{"status":"firing","receiver":"webhook-secure","alerts":[{"labels":{"alertname":"Test"}}]}'''
secret=b"WEBHOOK_SHARED_SECRET"
print(hmac.new(secret, body, hashlib.sha256).hexdigest())
PY
)
curl -k -X POST https://webhook.example.com/alert \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TOKEN_123456" \
-H "X-Signature: $SIG" \
-d "$BODY"
预期效果:接收端返回 200 ok,日志输出告警摘要。
传输与证书校验(mTLS 可选示例)#
/etc/alertmanager/alertmanager.yml
receivers:
- name: "webhook-mtls"
webhook_configs:
- url: "https://webhook.example.com/alert"
http_config:
tls_config:
ca_file: /etc/alertmanager/ca.crt
cert_file: /etc/alertmanager/client.crt
key_file: /etc/alertmanager/client.key
命令解释
- ca_file: 服务器 CA,防止中间人。
- cert_file/key_file: 客户端证书,Webhook 端可验证来源。
接收端安全策略示例(Nginx 前置)#
/etc/nginx/conf.d/webhook.conf
server {
listen 443 ssl;
server_name webhook.example.com;
ssl_certificate /etc/nginx/ssl/webhook.crt;
ssl_certificate_key /etc/nginx/ssl/webhook.key;
client_max_body_size 1m;
location /alert {
limit_req_zone $binary_remote_addr zone=wh_zone:10m rate=3r/s;
limit_req zone=wh_zone burst=5 nodelay;
proxy_pass http://127.0.0.1:9001;
proxy_set_header X-Real-IP $remote_addr;
}
}
排错与验证#
常见问题#
1) 401/403
- 令牌或签名不匹配。
2) TLS 握手失败
- 证书 CN/SAN 与域名不一致,或 CA 未信任。
3) 重试风暴
- Webhook 未返回 2xx 或超时。
快速排查命令#
# 检查 Alertmanager 到 Webhook 的 TLS
curl -v https://webhook.example.com/alert
# 查看 Alertmanager 发送记录
journalctl -u alertmanager -n 50
# 验证 Nginx 限流状态
grep "limit_req" /var/log/nginx/error.log
告警最小化与脱敏示例#
/etc/prometheus/alert.rules.yml
groups:
- name: secure-alerts
rules:
- alert: HostDown
expr: up == 0
labels:
severity: critical
annotations:
summary: "实例不可达"
description: "实例 {{ $labels.instance | reReplaceAll \"([0-9]+\\.[0-9]+)\\.[0-9]+\\.[0-9]+\" \"$1.*.*\" }} 不可达"
练习#
1) 将 Alertmanager UI 仅对内网开放,外网访问返回 403。
2) 给 Webhook 增加 X-Signature 校验,并验证错误签名被拒绝。
3) 调整 limit_req,模拟 50 并发请求并观察限流日志。
4) 启用 mTLS,验证无客户端证书时请求失败。