feat(monitoring): scrape alertmanager, alert on failed delivery; fix stale README
Alertmanager was configured as an alerting target but never scraped, so its own metrics were absent: a silently breaking alert chain could not report itself — the same blind spot as a missing series, now at the end of the chain. Adds the operating_alertmanager scrape job and AlertDeliveryFailing on alertmanager_notifications_failed_total. The README still claimed alert delivery was deliberately muted via a room=security null receiver. That route is gone; alertmanager.yml routes everything to the matrix receiver, so the backup alerts added yesterday do get delivered. Documentation asserting the opposite is dangerous in both directions, so it now states the current wiring and keeps the alert-storm history as background. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+19
-23
@@ -99,32 +99,28 @@ State (`cve_exporter_state`-Volume) -- daher kommt die Spalte
|
|||||||
Bei Stack-Aenderungen `cve/images.txt` nachziehen, sonst scannt die Pipeline
|
Bei Stack-Aenderungen `cve/images.txt` nachziehen, sonst scannt die Pipeline
|
||||||
an der Realitaet vorbei.
|
an der Realitaet vorbei.
|
||||||
|
|
||||||
### Bekanntes Problem: Alarm-Zustellung ist stummgeschaltet
|
### Alarm-Zustellung (frueher stummgeschaltet — seit gitops#51 wieder scharf)
|
||||||
|
|
||||||
**Die CVE-Regeln laufen, die Alarme werden aber bewusst nicht zugestellt.**
|
**Stand 2026-08-15: Alarme werden zugestellt.** `alertmanager.yml` hat nur noch die
|
||||||
In `alertmanager.yml` routet `room="security"` derzeit auf den Null-Receiver.
|
Default-Route auf den `matrix`-Receiver; die frueher hier beschriebene
|
||||||
|
`room="security"`-Route auf den Null-Receiver existiert nicht mehr. Alarme **ohne**
|
||||||
|
`room`-Label (u.a. die `axion-basics`- und `axion-backup`-Gruppen) laufen ueber
|
||||||
|
diese Default-Route.
|
||||||
|
|
||||||
Grund: `TrivyCriticalVuln` und `TrivyHighVuln` erzeugen eine Alarm-Instanz
|
Historie, damit der Grund der damaligen Stummschaltung nicht verlorengeht: die
|
||||||
**pro CVE pro Image**. Beim ersten Scan-Durchlauf waren das bei 14 von 29
|
CVE-Regeln erzeugten je eine Alarm-Instanz **pro CVE pro Image** (beim ersten Lauf
|
||||||
Images bereits 59 CRITICAL und 445 HIGH. Da `group_by: [alertname, instance]`
|
59 CRITICAL + 445 HIGH), `matrix-alerts.py` schickte eine Nachricht pro Alarm,
|
||||||
alle in *eine* Gruppe legt und `matrix-alerts.py` **eine Matrix-Nachricht pro
|
Synapse rate-limitete nach ~10 Nachrichten mit 429, und weil `save_state()` hinter
|
||||||
Alarm** schickt, wird daraus ein Nachrichten-Schwall. Verschaerfend:
|
der Sende-Schleife stand, wiederholte Alertmanager die komplette Gruppe mit noch
|
||||||
`save_state()` steht in `do_POST` hinter der Sende-Schleife -- bricht ein Send
|
leerer Deduplizierung. Behoben durch Aggregation auf `count by (target, severity)`
|
||||||
ab (Synapse rate-limitet nach ~10 Nachrichten mit 429), wird der State nicht
|
(eine Instanz je Image statt je CVE); Details im Dashboard `cve-overview`.
|
||||||
gespeichert, der Receiver antwortet 502 und Alertmanager wiederholt die
|
Vollstaendige Historie: gitops#51 / AAR 2026-08-01.
|
||||||
komplette Gruppe. Die Fingerprint-Deduplizierung ist beim Retry noch leer,
|
|
||||||
also wiederholt sich das.
|
|
||||||
|
|
||||||
Zum Scharfschalten sind **beide** Punkte noetig:
|
**Zustellfehler sind seit 2026-08-15 selbst ueberwacht:** Prometheus scrapt
|
||||||
|
Alertmanager (`operating_alertmanager`) und `AlertDeliveryFailing` schlaegt an,
|
||||||
1. Zustellung buendeln -- entweder `matrix-alerts.py` auf eine Sammelnachricht
|
wenn `alertmanager_notifications_failed_total` steigt. Vorher war Alertmanager zwar
|
||||||
pro Webhook-Batch umbauen (alle fuenf Pflichtfelder je CVE als eine Zeile),
|
Alarm-Ziel, aber kein Scrape-Target — eine reissende Alarmkette haette sich also
|
||||||
oder die Regeln auf `count by (target, severity)` aggregieren und die
|
selbst nicht melden koennen.
|
||||||
CVE-Details im Dashboard lassen.
|
|
||||||
2. `save_state()` inkrementell nach jedem erfolgreichen Send, plus
|
|
||||||
429-Behandlung mit `Retry-After`.
|
|
||||||
|
|
||||||
Danach die `room="security"`-Route aus `alertmanager.yml` entfernen.
|
|
||||||
|
|
||||||
### Kleinere offene Punkte der Pipeline
|
### Kleinere offene Punkte der Pipeline
|
||||||
|
|
||||||
|
|||||||
@@ -147,3 +147,15 @@ groups:
|
|||||||
severity: critical
|
severity: critical
|
||||||
annotations:
|
annotations:
|
||||||
summary: "Ein Backup-/Probe-CronJob fehlt im Cluster — Sicherung oder Wiederherstellungs-Nachweis laeuft nicht mehr"
|
summary: "Ein Backup-/Probe-CronJob fehlt im Cluster — Sicherung oder Wiederherstellungs-Nachweis laeuft nicht mehr"
|
||||||
|
|
||||||
|
# Die Alarmkette meldet ihr eigenes Reissen. Ironie inklusive: schlaegt die
|
||||||
|
# Zustellung komplett fehl, kommt auch dieser Alarm nicht an - er ist dann
|
||||||
|
# aber in Prometheus/Grafana sichtbar, statt dass gar nichts existiert.
|
||||||
|
# Teilausfaelle (ein Receiver von mehreren, Rate-Limit 429) meldet er sauber.
|
||||||
|
- alert: AlertDeliveryFailing
|
||||||
|
expr: increase(alertmanager_notifications_failed_total[15m]) > 0
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
annotations:
|
||||||
|
summary: "Alertmanager konnte Benachrichtigungen nicht zustellen ({{ $labels.integration }}) — Alarme laufen ins Leere"
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,14 @@ scrape_configs:
|
|||||||
static_configs:
|
static_configs:
|
||||||
- targets: ["cadvisor:8080"]
|
- targets: ["cadvisor:8080"]
|
||||||
|
|
||||||
|
# Alertmanager-Eigenmetriken. Ohne diesen Job sind ZUSTELLfehler unsichtbar:
|
||||||
|
# Prometheus kennt alertmanager zwar als Alarm-Ziel (oben unter alerting:),
|
||||||
|
# scrapt ihn aber nicht - eine still reissende Alarmkette waere also genau das,
|
||||||
|
# was niemand meldet. Liefert u.a. alertmanager_notifications_failed_total.
|
||||||
|
- job_name: "operating_alertmanager"
|
||||||
|
static_configs:
|
||||||
|
- targets: ["alertmanager:9093"]
|
||||||
|
|
||||||
- job_name: "operating_traefik"
|
- job_name: "operating_traefik"
|
||||||
metrics_path: "/metrics"
|
metrics_path: "/metrics"
|
||||||
static_configs:
|
static_configs:
|
||||||
|
|||||||
Reference in New Issue
Block a user