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>
6.6 KiB
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 verifygibt 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_SEARCHstatt 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=. EinEnvironment=im Unit-File ist für jeden Benutzer übersystemctl showlesbar.
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:
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
xattrgehen 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).