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>
154 lines
6.6 KiB
Markdown
154 lines
6.6 KiB
Markdown
# Linux-Agent (Phase 6)
|
|
|
|
Phase 6 teilt sich fast alles mit Phase 5 — dieselbe Aufnahme, dieselbe
|
|
Lebendmeldung, dieselbe Auftragsübermittlung, dieselbe Engine. Was sie
|
|
eigenständig macht, sind die Eigenheiten eines Unix-Dateisystems: Sockets,
|
|
benannte Pipes, Gerätedateien, harte Verknüpfungen — und ein Dienstmodell, das
|
|
sich einsperren lässt.
|
|
|
|
## Der Fund: Ein Socket ist kein Fehler
|
|
|
|
Bis zu dieser Phase galt **jedes** Erfassungsproblem als übergangenes Objekt und
|
|
machte den Lauf damit zum Teilfehler. Auch ein Socket.
|
|
|
|
Auf einem Linux-System ist das ein Dauerzustand: In `/var/run` und `/tmp` liegen
|
|
ständig Sockets. Wer `/var` sichert, bekäme bei **jedem** Lauf einen Teilfehler.
|
|
Nach einer Woche klickt niemand mehr einen Teilfehler an — und dann fällt auch
|
|
der echte nicht mehr auf. Dieselbe Alarmmüdigkeit, gegen die Phase 14 und 16
|
|
gebaut sind.
|
|
|
|
Die Unterscheidung, die jetzt gilt:
|
|
|
|
| Objekt | Ergebnis | Warum |
|
|
| --- | --- | --- |
|
|
| Nicht lesbare Datei | **Datenverlust** → Teilfehler | Dort waren Daten, und sie fehlen |
|
|
| Gesperrtes Verzeichnis | **Datenverlust** → Teilfehler | Dasselbe |
|
|
| Socket | Vermerk, kein Fehler | Endpunkt eines laufenden Prozesses, kein Inhalt |
|
|
| Benannte Pipe (FIFO) | Vermerk, kein Fehler | Hat keinen Inhalt zum Sichern |
|
|
| Block-/Zeichengerät | Vermerk, kein Fehler | Dasselbe |
|
|
|
|
**Verschwiegen wird trotzdem nichts.** Die Zusammenfassung nennt sie auch im
|
|
Erfolgsfall:
|
|
|
|
```
|
|
Erfolgreich: 4 Dateien, 1 Verzeichnisse gesichert. 2 Objekt(e) ohne sicherbaren
|
|
Inhalt (Sockets, Pipes, Gerätedateien) wurden übergangen; das ist kein Fehler.
|
|
```
|
|
|
|
Und die Meldung benennt den Typ in Worten. `prw-r--r--` sagt einem Betreiber
|
|
nichts; „benannte Pipe (FIFO)" sagt ihm, dass er nichts zu tun hat.
|
|
|
|
### Was der Agent mit einer FIFO **nicht** tut
|
|
|
|
Er liest sie nicht. Das ist der klassische Backup-Bug: Ein Leseversuch auf einer
|
|
benannten Pipe ohne Schreiber blockiert **für immer**. Die Erfassung entscheidet
|
|
anhand des Dateityps, bevor sie öffnet — ein Test mit Zeitgrenze hält das fest.
|
|
|
|
## Symbolische Verweise werden erfasst, nicht verfolgt
|
|
|
|
Ein Verweis kommt als Verweis ins Backup und wird als Verweis zurückgeschrieben.
|
|
Verfolgte die Erfassung ihn, geriete sie bei einem Verweis auf ein
|
|
übergeordnetes Verzeichnis in eine Schleife — und ein Verweis nach `/` zöge das
|
|
ganze System ins Backup.
|
|
|
|
## Harte Verknüpfungen: der Inhalt kommt zurück, die Verknüpfung nicht
|
|
|
|
Zwei Namen derselben Datei erscheinen als **zwei Dateien**. Der Inhalt liegt
|
|
dank Deduplizierung nur einmal im Repository — der Platzbedarf im Backup ist
|
|
also derselbe.
|
|
|
|
Nach einer Wiederherstellung sind es jedoch **zwei unabhängige Dateien**:
|
|
|
|
```
|
|
Quelle: 2 Verknüpfungen
|
|
Ziel: 1 Verknüpfung
|
|
```
|
|
|
|
Das kostet Platz am Ziel und ändert die Bedeutung: Eine Änderung an der einen
|
|
wirkt nicht mehr auf die andere. Für die meisten Anwendungsfälle ist das
|
|
unerheblich; wer Paketverwaltungen oder Deduplizierungsbäume sichert, sollte es
|
|
wissen.
|
|
|
|
Umsetzbar wäre es — Inode-Nummer erfassen und beim Zurückschreiben `link()`
|
|
statt Kopie —, aber es griffe in das Manifestformat ein. Es steht hier als
|
|
benannte Grenze, nicht als Versehen.
|
|
|
|
## Die systemd-Einheit hatte drei Fehler
|
|
|
|
`deployment/syncova-agent.service` war gut gehärtet und **hätte nicht
|
|
funktioniert**:
|
|
|
|
**`--state /var/lib/syncova-agent`** — das ist ein Verzeichnis. Der Parameter
|
|
erwartet eine Datei. Der Agent hätte beim Start gemeldet, er sei bereits
|
|
registriert (ein vorhandenes Verzeichnis sieht für ihn wie eine Zustandsdatei
|
|
aus), und wäre ohne Token gelaufen.
|
|
|
|
**Kein `ReadWritePaths` für das Repository.** Bei `ProtectSystem=strict` ist das
|
|
gesamte Dateisystem nur lesbar. Der Agent hätte die Quelle vollständig gelesen
|
|
und gehasht — und dann keinen einzigen Block ablegen können. Der Fehler wäre
|
|
erst am Ende des Laufs aufgetreten.
|
|
|
|
**`RestrictAddressFamilies` ohne `AF_UNIX`.** Auf Systemen mit
|
|
`systemd-resolved` oder `nscd` läuft die Namensauflösung über einen
|
|
Unix-Socket. Ohne `AF_UNIX` findet der Agent seinen Server nicht und meldet
|
|
einen Netzfehler, während das Netz einwandfrei arbeitet.
|
|
|
|
Alle drei sind behoben. Der Repositorypfad ist an die eigene Anlage anzupassen —
|
|
liegt das Repository auf einer Freigabe, gehört deren Einhängepunkt in
|
|
`ReadWritePaths`.
|
|
|
|
> Die Einheit ist weiterhin **nicht auf einem Linux-System geprüft**.
|
|
> `systemd-analyze verify` gibt es auf macOS nicht.
|
|
|
|
## Was die Härtung leistet
|
|
|
|
Der Agent liest fremde Daten und spricht mit dem Netz — genau die Art Dienst,
|
|
die man einsperrt:
|
|
|
|
- **`CAP_DAC_READ_SEARCH` statt root.** Er darf fremde Dateien lesen, sonst
|
|
nichts. Der Unterschied ist beträchtlich: Lesen ist etwas anderes als
|
|
Alleskönnen.
|
|
- **`ProtectSystem=strict`, `ProtectHome=read-only`**, Schreibrechte nur auf
|
|
Zustand und Repository.
|
|
- **`MemoryDenyWriteExecute`, `RestrictSUIDSGID`, `NoNewPrivileges`,
|
|
Systemaufruffilter** — die üblichen Riegel gegen Ausnutzung eines Fehlers im
|
|
Dienst selbst.
|
|
- **`Nice=10`, `IOSchedulingClass=idle`** — ein Backup soll dem laufenden
|
|
Betrieb nicht die Maschine wegnehmen.
|
|
- **Das Schlüsselmaterial steht in einer Datei, nicht in `Environment=`.** Ein
|
|
`Environment=` im Unit-File ist für jeden Benutzer über `systemctl show`
|
|
lesbar.
|
|
|
|
## Nachweis
|
|
|
|
Auf einem Quellverzeichnis mit gewöhnlichen Dateien, einer harten Verknüpfung,
|
|
einem symbolischen Verweis, einer benannten Pipe, einem Unix-Socket und einem
|
|
gesperrten Verzeichnis:
|
|
|
|
```text
|
|
Erfassung 4 Dateien, 2 Objekte ohne sicherbaren Inhalt vermerkt
|
|
Sicherung Erfolg (Exit 0) — kein Teilfehler wegen Socket und Pipe
|
|
Restore 4 Dateien bitgenau, Symlink erhalten, Rechte erhalten
|
|
Sonderdateien im Ziel: keine — korrekt
|
|
Harte Verknüpfung: Quelle 2, Ziel 1 — dokumentierte Grenze
|
|
```
|
|
|
|
Der gesperrte Ordner erzeugte dabei erwartungsgemäß einen Rechtefehler und damit
|
|
einen Teilfehler — bis er freigegeben wurde. Genau diese Unterscheidung ist der
|
|
Kern der Phase.
|
|
|
|
## Was offen bleibt
|
|
|
|
- **Die systemd-Einheit ist ungeprüft.** Sie ist inhaltlich korrigiert, aber nie
|
|
auf einem Linux-System geladen worden.
|
|
- **Erweiterte Attribute und ACLs werden nicht gesichert.** POSIX-ACLs,
|
|
SELinux-Kontexte und `xattr` gehen verloren. Für eine Wiederherstellung auf
|
|
demselben System ist das meist unerheblich, für eine Systemwiederherstellung
|
|
nicht.
|
|
- **Keine Sicherung offener Dateien mit konsistentem Stand.** Es gibt keinen
|
|
Schattenkopie-Mechanismus wie VSS unter Windows; eine Datenbank, die während
|
|
der Sicherung schreibt, landet in dem Zustand, in dem sie gerade ist. Für
|
|
Datenbanken gehört ein eigener Ablauf davor (Dump oder Snapshot des
|
|
Dateisystems).
|
|
- **Harte Verknüpfungen werden aufgelöst** (siehe oben).
|