syncova-backup/docs/alerting.md
Jerrit Fritzsche 610719c316
Some checks failed
CI / Backend (Go) (push) Failing after 3m7s
CI / Frontend (React/TypeScript) (push) Successful in 37s
CI / Sicherheitsprüfungen (push) Successful in 44s
Syncova Backups V1
Enterprise-Backup-, Recovery-, Verification-, Security- und
Monitoring-Plattform fuer Proxmox VE, Windows, Linux und Dateisysteme.

Der Leitsatz, der fast jede Entscheidung erklaert: Ein Backup gilt erst als
vertrauenswuerdig, wenn Integritaet geprueft und Wiederherstellbarkeit
nachgewiesen wurde. Deshalb steigt ein Wiederherstellungspunkt erst nach einem
tatsaechlich durchgefuehrten Restore-Test auf "recoverable", und Unbekanntes
geht in keine Bewertung als "gut" ein.

Umfang (Phasen 0-23):

- Repository Engine: inhaltsadressierte Bloecke, atomares Commit-Protokoll,
  Katalogaufbau allein aus den Manifesten — ohne Datenbank
- Backup Engine: inhaltsabhaengiges Chunking, Deduplizierung trotz
  Verschluesselung, zstd, AES-256-GCM, Streaming mit Gegendruck
- Agenten fuer Windows und Linux mit Auftragsabholung (Pull-Modell)
- Proxmox-Provider mit beiden Zugriffswegen auf die Sicherungsarchive
- Scheduler, Recovery Engine mit Pruefpunkt, Verification, Unveraenderlichkeit
- Weboberflaeche, Kennzahlen, Meldungen, Berichte, Security Center,
  Ransomware-Heuristik (meldet, handelt nie)
- Disaster Recovery, Haertung, Leistungsmessung, Chaos Testing
- Eingefrorene Vertraege fuer API, Migrationen, Backup-Format und Repository
- Auslieferungspaket fuer linux/amd64, linux/arm64 und windows/amd64

Nicht enthalten und als solches gekennzeichnet: Kapazitaetsprognose, Backup
Copy, Changed Block Tracking bei Proxmox, erweiterte Attribute und ACLs.

Gebaut, aber nie auf echter Hardware gefahren: der Windows-Dienst, die
systemd-Einheit und der verpflichtende Proxmox-Meilenstein — ob eine
wiederhergestellte VM startet, ist ungeprueft. Einzelheiten in CHANGELOG.md
und docs/release-candidate.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 09:10:54 +02:00

186 lines
8.6 KiB
Markdown

# Meldungen und Benachrichtigungen
Phase 14. Der Teil der Anlage, der sagt, wann jemand hinsehen muss.
Das Meldungswesen hat einen Feind, und es ist nicht der fehlende Alarm:
> Es ist der Alarm, den niemand mehr liest.
Ein System, das jede Minute dieselbe Meldung erzeugt, wird nach drei Tagen
weggeklickt — und dann fehlt die eine, auf die es ankam. Jede Entscheidung
dieser Phase ist an dieser Beobachtung gemessen.
## Zwei Eigenschaften tragen alles
### Eine Ursache, eine Meldung
Jeder Befund trägt einen Fingerabdruck aus Regel und betroffenem Gegenstand —
**nicht** aus dem Zeitpunkt. Ein Teilindex macht eine zweite offene Meldung zur
selben Ursache unmöglich:
```sql
CREATE UNIQUE INDEX alerts_single_open_idx ON alerts (fingerprint)
WHERE status IN ('open', 'acknowledged');
```
Die Regel steht in der Datenbank und nicht in der Anwendung: Zwischen einem
Nachsehen und einem Schreiben passt ein zweiter Control-Server. Der wiederholte
Befund erhöht stattdessen einen Zähler — und der ist die eigentliche Auskunft:
Einmal ist ein Zwischenfall, zwanzigmal ein Zustand.
### Meldungen lösen sich selbst auf
Jede Regel liefert die Menge der **derzeit** zutreffenden Befunde. Was darin
fehlt, aber noch offensteht, wird geschlossen — automatisch, mit dem Vermerk
„Die Ursache besteht nicht mehr."
Ohne diesen Schritt bleibt jede Meldung stehen, bis jemand sie wegklickt. Nach
zwei Wochen steht dort eine Liste erledigter Probleme, und die eine aktuelle geht
darin unter.
Der Auswerter beschreibt deshalb den **Ist-Zustand**, statt Ereignisse zu zählen.
### Bestätigen heißt nicht Erledigen
Eine bestätigte Meldung bleibt offen und in der Liste unerledigter Vorgänge. Sie
wird weiter aktualisiert, solange die Ursache besteht. Wäre „bestätigen"
dasselbe wie „schließen", verschwände der Zustand aus der Übersicht, obwohl er
weiterbesteht.
Wer eine Meldung von Hand schließt, bekommt gesagt: *„Besteht die Ursache
weiterhin, erzeugt die nächste Auswertung eine neue Meldung."*
## Die elf Regeln
| Regel | Schwere | Auslöser |
| --- | --- | --- |
| `backup_failure` | hoch / Warnung | Letzter Lauf gescheitert oder mit Teilfehler |
| `repeated_backup_failure` | kritisch | Zwei Fehlschläge in Folge |
| `repository_unavailable` | kritisch | Repository als nicht erreichbar geführt |
| `repository_filling` | Warnung | Belegung ≥ 80 % |
| `repository_full` | kritisch | Belegung ≥ 90 % |
| `agent_offline` | hoch | 15 Minuten ohne Lebendmeldung |
| `rpo_violation` | hoch | Letzte erfolgreiche Sicherung älter als die RPO-Vorgabe |
| `verification_failure` | kritisch | Backup als `corrupted` eingestuft |
| `unusual_change_rate` | hoch | ≥ 90 % neue Daten in einer Zusatzsicherung |
| `immutable_copy_missing` | Warnung | Wiederherstellungspunkte ohne Löschschutz |
| `certificate_expiry` | — | **Wird nicht geprüft** |
### Warum die Zertifikatsregel schweigt
Die Agenten weisen sich über Betriebstokens aus, nicht über Zertifikate. Die
Tabelle `agent_certificates` wird von keiner Stelle beschrieben — die Regel
könnte nie auslösen.
Eine Regel, die dauerhaft schweigt, ist gefährlicher als keine: Sie erweckt den
Eindruck, es werde geprüft. Sie erscheint deshalb im Regelwerk mit dieser
Begründung und wird nicht ausgewertet.
### Warum die Ransomware-Regel „Verdacht" heißt
`unusual_change_rate` erkennt, dass bei einer Zusatzsicherung fast alle Daten neu
waren, obwohl die Quelle bereits gesichert war. Die Deduplizierung greift dann
plötzlich nicht mehr, weil kein Block dem vorigen Backup gleicht.
Massenhafte Verschlüsselung durch Schadsoftware sieht genau so aus. Ein großes
Update, eine Datenbankreorganisation oder ein Kettenwechsel aber auch.
Die Meldung sagt das ausdrücklich und rät, die Änderung zu prüfen, **bevor**
ältere Wiederherstellungspunkte gelöscht werden. Eine Anlage, die „Ransomware
erkannt" meldet und danebenliegt, wird beim nächsten Mal ignoriert — und dann
liegt sie richtig.
### Die Schwellen
Sie stehen beisammen im Code, weil ihre Wahl den Wert des ganzen Meldungswesens
bestimmt:
- **Zwei Fehlschläge**, nicht drei: Einer kann ein Netzwerkzucken sein, zwei
hintereinander sind ein Zustand.
- **15 Minuten** ohne Lebendmeldung bei einem Meldeabstand von einer Minute: Ein
zweiminütiger Netzwerkausfall weckt niemanden.
- **90 % neue Daten** und mindestens 100 MB: Ohne Untergrenze meldete jede kleine
Quelle mit drei geänderten Dateien einen Verdacht.
- **80 % / 90 % Belegung**, getrennte Bereiche: Ein zu 95 % belegtes Repository
erzeugt sonst zwei Meldungen zur selben Ursache.
## Zustellung
Zwei Kanäle, beide mit echter Auslieferung — geprüft gegen einen echten
SMTP-Server und einen echten HTTP-Empfänger, nicht gegen Attrappen.
| Kanal | Zustellung |
| --- | --- |
| `email` | SMTP; Schweregrad in der Betreffzeile, Meldungskennung im Rumpf |
| `webhook` | HTTP-POST mit JSON; `Authorization: Bearer …` zur Prüfung der Herkunft |
- **Nur neue Meldungen werden zugestellt.** Eine aktualisierte nicht — sonst
bekäme der Bereitschaftsdienst alle fünf Minuten dieselbe Mail, solange der
Zustand anhält. Ein Eindeutigkeitsindex sichert das zusätzlich ab.
- **Jeder Kanal hat eine Schwelle.** Standard ist `high`. Ohne sie bekäme der
Bereitschaftsdienst nachts jede Information; nach einer Woche schaltet er die
Benachrichtigungen ab, und dann kommt auch die kritische nicht mehr an.
- **Webhook verlangt HTTPS.** Eine Meldung über unverschlüsseltes HTTP verrät
einem Mitleser, welche Anlage gerade nicht gesichert wird. `allow_insecure`
ist der ausdrückliche Ausweg; einen Schalter „Zertifikat egal" gibt es nicht.
- **Der Schweregrad steht im Betreff.** Wer nachts auf sein Telefon sieht, liest
die Betreffzeile und sonst nichts.
- **Fehlgeschlagene Zustellungen werden am Kanal vermerkt** (`last_delivery_error`,
`consecutive_failures`). Ein Kanal, der seit Wochen nichts zustellt, ist
genauso schlimm wie eine fehlende Meldung — und ohne dieses Feld fällt es
niemandem auf.
- **Zugangsgeheimnisse werden verschlüsselt abgelegt** und gehen nie in eine
API-Antwort, ein Protokoll oder eine Fehlermeldung.
## Endpunkte
| Methode | Pfad | Recht |
| --- | --- | --- |
| GET | `/api/v1/alerts` | `alerts.read` |
| GET | `/api/v1/alerts/summary` | `alerts.read` |
| GET | `/api/v1/alerts/{id}` | `alerts.read` |
| POST | `/api/v1/alerts/{id}/acknowledge` | `alerts.write` |
| POST | `/api/v1/alerts/{id}/resolve` | `alerts.write` |
| GET | `/api/v1/notification-channels` | `settings.read` |
| POST | `/api/v1/notification-channels` | `settings.write` |
| DELETE | `/api/v1/notification-channels/{id}` | `settings.write` |
Die Kanäle hängen am Einstellungsrecht, nicht am Meldungsrecht: Wer
Benachrichtigungen umleitet, kann erreichen, dass niemand mehr von einem Ausfall
erfährt. Anlegen und Löschen werden auditiert.
`/alerts/summary` liefert die Lage **und das Regelwerk**. Eine leere
Meldungsliste ist erst dann eine gute Nachricht, wenn man weiß, was überhaupt
geprüft wird.
## Nachgewiesen
Gegen den laufenden Dienst:
| Nachweis | Ergebnis |
| --- | --- |
| Regelwerk | 10 von 11 Regeln werden geprüft, die elfte mit Begründung |
| Erkennung | 12 Meldungen aus echten Zuständen (6 kritisch, 3 ernst) |
| Deduplizierung | Nach mehreren Durchgängen eine Meldung je Ursache, Zähler steigt |
| Selbstauflösung | Zwei Repositories wieder erreichbar → beide Meldungen automatisch geschlossen, die anderen zwei blieben offen |
| Zustellung | Webhook-Empfänger erhielt Meldung samt Bearer-Token |
| Keine Doppelzustellung | Nach weiterem Durchgang weiterhin genau eine Zustellung |
| Schwelle | Null Zustellungen unterhalb `critical` an den kritischen Kanal |
| Geheimnis | Erscheint nicht in der API-Antwort |
| Bestätigen | Zustand `acknowledged`, Meldung bleibt in der Liste; zweiter Versuch 409 |
## Bekannte Grenzen
- **Keine Wiederholung fehlgeschlagener Zustellungen.** Ein nicht erreichbarer
Empfänger bleibt es meist auch beim zweiten Versuch, und die Schleife soll
nicht daran hängen. Der Kanalzustand macht das Problem sichtbar.
- **Keine Ruhezeiten und keine Eskalation.** Eine Meldung geht sofort an alle
passenden Kanäle; es gibt keine Wartungsfenster für Benachrichtigungen und
keine Weiterleitung, wenn niemand reagiert.
- **Regeln und Schwellen sind fest.** Sie stehen im Code, nicht in der Datenbank.
Eine Oberfläche zum Ändern gäbe es erst, wenn klar ist, welche Schwellen sich
in der Praxis als falsch erweisen.
- **Kein Test der Kanäle** vor dem Ernstfall. Ob eine Adresse stimmt, zeigt sich
bei der ersten echten Meldung.
- **Die Zertifikatsregel** wartet auf eine Zertifikatsverwaltung für Agenten.