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>
12 KiB
Agent
Dieses Dokument beschreibt den aktuell implementierten Stand nach Phase 5.
Stand: was geprüft ist und was nicht
Der Agent wurde auf macOS entwickelt. Das bestimmt, was belegt ist:
| Bereich | Stand |
|---|---|
| Dateierfassung, Muster, Rechtefehler | auf Unix geprüft |
| Aufnahme, Betriebstoken, Sperre, Rotation | gegen die echte Datenbank geprüft |
| Lebendmeldung, Netzunterbrechung, Wiederaufnahme | real geprüft |
| Kreuzübersetzung für windows/amd64 und linux/amd64 | geprüft |
| Windows-Dienstanbindung | ungeprüft — siehe unten |
| systemd-Unit | geschrieben, nicht auf einem Linux-System erprobt |
Das Exit-Kriterium der Phase 5 lautet: „Ein Windows-System kann zuverlässig gesichert und wiederhergestellt werden." Das ist auf dieser Plattform nicht nachweisbar und deshalb nicht erfüllt. Für Windows fehlen: die Anmeldung am Dienstverwalter, das Verhalten bei Dienst-Stopp und Neustart, die Rechte des Dienstkontos und die Behandlung von Windows-Dateisystemeigenheiten (Laufwerksbuchstaben, ADS, gesperrte Dateien, VSS).
Bis das auf einem Windows-System nachgeholt ist, gilt Phase 5 dort als offen. service_windows.go benennt das im Quelltext und lässt den Agent im Vordergrund laufen — ein ungeprüfter Dienst darf nicht als lauffähig ausgegeben werden (PROMPT.md §138).
Zwei Tokenarten
Der gesamte Aufbau folgt PROMPT.md §59: Ein kompromittierter Agent darf nicht automatisch vollständigen Zugriff auf die Backup-Infrastruktur erhalten.
| Aufnahme-Token | Betriebstoken | |
|---|---|---|
| Gültigkeit | einmalig, standardmäßig 1 Stunde | dauerhaft |
| Zweck | ausschließlich Registrierung | Lebendmeldung, später Backups |
| Ausstellung | durch Benutzer mit agents.enroll |
durch den Server bei der Registrierung |
| Ablage | nur als Hash | nur als Hash |
| Widerruf | durch Einlösen verbraucht | einzeln, ohne andere Agents zu stören |
Der Agent bestimmt seinen Namen nicht selbst — er steht im Aufnahme-Token. Sonst könnte er sich als ein anderes System ausgeben.
Beide Tokenarten sind streng getrennt. Real nachgewiesen:
Agent-Token gegen /users, /roles, /audit-events, /agents → 401
Benutzer-Token gegen /agents/heartbeat → 401
Gesperrter Agent, altes Token → 401
Aufnahme-Token als Betriebstoken → abgelehnt
Registrierung
# 1. Administration stellt ein Aufnahme-Token aus
POST /api/v1/agents/enrollment-tokens {"agent_name": "Server01"}
# 2. Auf dem zu sichernden System
syncova-agent register --server https://syncova.example.local --token <aufnahme-token>
# 3. Der Agent läuft
syncova-agent run
Das Betriebstoken landet in agent-state.json neben dem Programm, mit Rechten 0600. Es liegt dort im Klartext, weil der Agent es bei jedem Start braucht und niemand zur Eingabe bereitsteht — wer diese Datei lesen kann, hat ohnehin bereits Zugriff auf das zu sichernde System.
Eine bestehende Aufnahme wird nicht überschrieben: der Agent verlöre sonst sein Token und wäre für den Server ein neues, unbekanntes System.
Verhalten bei Netzunterbrechung
Real geprüft: Server gestoppt → Agent meldet den Ausfall und versucht es weiter → Server zurück → Verbindung wiederhergestellt.
- Wartezeit wächst von 5 Sekunden bis höchstens 5 Minuten. Ohne Obergrenze bliebe der Agent nach einer längeren Störung minutenlang stumm, obwohl der Server längst wieder da ist.
- Die Logmeldung wiederholt sich nur selten (erster Ausfall, dann jede zehnte). Eine längere Störung soll das Log nicht fluten.
- Ein abgelehntes Token beendet den Agent mit klarer Meldung. Es behebt sich nicht durch Warten: der Agent wurde gesperrt oder sein Token gewechselt. Weiterversuchen erzeugte nur Last.
Dateierfassung
syncova-agent discover --path /daten --exclude "*.tmp,logs" --list
- Probleme brechen den Lauf nicht ab, werden aber nie verschwiegen. Eine gesperrte Datei darf nicht das ganze Backup verhindern — aber ein Backup mit übergangenen Dateien ist ein Teilfehler, kein Erfolg (PROMPT.md §140). Das Kommando liefert dann einen Exit-Status ungleich 0.
- Rechtefehler werden gesondert ausgewiesen, weil sie fast immer eine Fehlkonfiguration des Dienstkontos bedeuten und nicht einen defekten Datenträger.
- Ausschluss geht vor Einschluss. Wer etwas ausdrücklich ausnimmt, meint es.
- Ein Muster ohne Platzhalter wirkt auf den Teilbaum:
logsschließt auchlogs/heute/app.logaus.logsammlung/bleibt unberührt. - Symbolischen Verweisen wird nicht gefolgt. Ein Verweis auf ein übergeordnetes Verzeichnis erzeugte eine endlose Schleife; ein Verweis nach außen zöge fremde Daten ins Backup. Das Ziel wird festgehalten, damit der Verweis wiederherstellbar bleibt.
- Die Reihenfolge ist fest sortiert, damit zwei Läufe vergleichbar sind.
- Pfade werden mit Schrägstrich abgelegt, damit ein unter Windows erstelltes Backup unter Linux nutzbar bleibt.
Geprüft mit 5 000 kleinen Dateien und einer 40-MiB-Datei.
Zusatzsicherung (inkrementell)
syncova-agent backup --repository /backup/repo-01 --path /daten --id nacht-1 --incremental
syncova-agent backup --repository /backup/repo-01 --path /daten --id nacht-2 --incremental --parent nacht-1
Ohne --parent wird das jüngste abgeschlossene Backup derselben Quelle gewählt. Maßgeblich ist die Quellkennung, nicht die Kette: wer denselben Pfad erneut sichert, meint dieselben Daten.
Was hier eigentlich eingespart wird
Ein zweiter Volllauf über unveränderte Daten legt dank Deduplizierung ohnehin 0 Byte ab. Die Zusatzsicherung spart also keinen Speicher — sie spart Lesen, Hashen, Komprimieren und Verschlüsseln. Gemessen an 190,7 MiB in 41 Dateien, von denen sich eine änderte:
| Vollsicherung | Zusatzsicherung | |
|---|---|---|
| Gelesen | 190,7 MiB | 4,8 MiB |
| Dauer | 1 815 ms | 133 ms |
Das ist der ganze Zweck. Bei einem Dateiserver mit Terabytes und täglich wenigen geänderten Dateien ist es der Unterschied zwischen einem Backupfenster von Stunden und einem von Minuten.
Das Manifest bleibt vollständig
Eine Zusatzsicherung erzeugt kein Manifest, das nur die Änderungen beschreibt. Es beschreibt den gesamten Bestand — unveränderte Objekte tragen die Blockverweise des Elternbackups. Daraus folgen drei Eigenschaften:
- Eine Wiederherstellung liest ein einziges Manifest. Es gibt keine Kette aufzulösen und damit keine Kette zu zerreißen.
- Das Löschen eines alten Backups kann ein neueres nicht beschädigen — dessen Manifest verweist selbst auf alle nötigen Blöcke, die Aufbewahrung sieht sie also als benutzt.
- Der Preis ist die Manifestgröße: sie wächst mit dem Bestand, nicht mit der Änderungsmenge (~200 Byte je Blockverweis, siehe
backup-engine.md).
Woran „unverändert" erkannt wird
Größe und Änderungszeitpunkt, wie bei rsync und restic. Das ist eine Abwägung und keine Gewissheit: wer eine Datei ändert und ihren Zeitstempel anschließend zurücksetzt, täuscht das Verfahren. Dagegen hilft nur die vollständige Sicherung. Verschwiegen wird die Grenze nicht — dafür steht sie hier.
Vier Fälle führen ausdrücklich zum erneuten Lesen:
- Der Zeitstempel liegt nicht vor dem Beginn des Elternbackups. Eine Datei, die während des Elternlaufs geschrieben wurde, kann bei sekundengenauer Zeitauflösung unverändert aussehen. Würde sie übernommen, ginge ihr neuer Inhalt still verloren — der schlimmste denkbare Fehler eines Backups. Im Zweifel wird gelesen.
- Die Art des Objekts wechselte (Datei ↔ Verzeichnis ↔ Verweis).
- Das Verweisziel änderte sich.
- Der Elterneintrag trägt keine Blockverweise, obwohl er eine Größe hat. Das darf nicht vorkommen; träte es ein, wäre die Übernahme ein stiller Datenverlust.
Eine reine Rechteänderung zählt gesondert (Nur Rechte): der Inhalt wird übernommen, die neuen Rechte werden vermerkt.
Fehlende Blöcke brechen den Lauf ab
Vor jeder Übernahme wird geprüft, ob der Block wirklich im Repository liegt. Ohne diese Prüfung entstünde ein Manifest, das sich als vollständiges Backup ausgibt, während seine Daten fehlen — und der Fehler fiele erst bei der Wiederherstellung auf, also genau dann, wenn es zu spät ist. Geprüft wird nur die Existenz, nicht der Inhalt: den prüft syncova-repo scan, und ihn hier zu lesen höbe den Zweck der Zusatzsicherung auf.
Löschungen
Was in der Quelle fehlt, fehlt im neuen Manifest — und wird beim Lauf namentlich genannt. Ein Backup, das eine verschwundene Datei stillschweigend weglässt, verwehrt genau die Beobachtung, für die man Backups anlegt. Aus dem Elternbackup kommt sie unverändert zurück; dafür gibt es die Aufbewahrung.
Betrieb als systemd-Dienst
useradd --system --home /var/lib/syncova-agent --shell /usr/sbin/nologin syncova-agent
install -d -o syncova-agent -g syncova-agent -m 0750 /var/lib/syncova-agent
install -d -o root -g root -m 0750 /etc/syncova
install -o root -g root -m 0600 deployment/syncova-agent.env.example /etc/syncova/agent.env
$EDITOR /etc/syncova/agent.env # Schlüssel und Serveradresse eintragen
install -o root -g root -m 0644 deployment/syncova-agent.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now syncova-agent
journalctl -u syncova-agent -f
Erläuterungen zu den nicht offensichtlichen Einstellungen der Unit:
EnvironmentFile=stattEnvironment=. Der Inhalt eines Unit-Files zeigtsystemctl showjedem Benutzer an — ein Verschlüsselungsschlüssel hätte dort nichts zu suchen.AmbientCapabilities=CAP_DAC_READ_SEARCH. Der Agent muss fremde Dateien lesen. Diese eine Fähigkeit erlaubt genau das, ohne ihm root zu geben; der Unterschied zwischen „darf alles lesen" und „darf alles" ist beträchtlich.Restart=on-failuremitStartLimitBurst=5. Ein abgelehntes Token behebt sich nicht durch Warten — der Agent beendet sich dann. Ohne Startversuchslimit liefe er in einer Neustartschleife und füllte nur das Journal.IOSchedulingClass=idle,Nice=10. Ein Backup soll dem laufenden Betrieb nicht die Maschine wegnehmen.ReadWritePaths=/var/lib/syncova-agentbeiProtectSystem=strict: Der Agent liest überall und schreibt an genau einer Stelle.
Ungeprüft: Die Unit wurde auf macOS geschrieben und dort nicht ausgeführt — systemd-analyze verify steht auf diesem Rechner nicht zur Verfügung. Sie ist vor dem Produktionseinsatz auf einem Linux-System zu prüfen.
Sonderdateien
Benannte Pipes, Sockets und Gerätedateien werden erfasst, vermerkt und nicht geöffnet. Eine Pipe zu öffnen blockiert, bis jemand hineinschreibt; ein Backup, das das täte, bliebe für immer stehen — ohne Fehlermeldung, ohne Fortschritt. Der Lauf gilt dadurch als Teilfehler und liefert Exit-Status ≠ 0: enthalten sind sie nicht, also darf niemand das annehmen.
Unterbrochene Läufe
Ein abgebrochener Lauf — Signal, Stromausfall, gefüllte Platte — hinterlässt kein Manifest. Übrig bleiben können Chunks; sie kosten Platz und werden vom nächsten Lauf wiederverwendet. Die Schreibsperre fällt, der nächste Lauf gelingt ohne Eingriff von Hand. Wäre das anders, fiele das Backup genau nach dem Ereignis aus, nach dem man es am nötigsten braucht.
Offene Punkte
Über die Windows-Lücke hinaus:
- Der Agent sichert nur auf Zuruf.
backupundrestorestehen als Kommandos bereit; die Auftragsübermittlung durch den Scheduler fehlt noch. Im Dienstbetrieb ist er weiterhin ein angemeldeter Beobachter — bis dahin plant man Läufe über systemd-Timer oder cron. - Keine Anmeldung über Zertifikate. Die Tabelle
agent_certificatesist angelegt, wird aber nicht genutzt. - Kein automatischer Tokenwechsel. Die Rotation ist umgesetzt, aber ein bewusster Eingriff — der Agent muss das neue Token erhalten, sonst kann er sich nicht mehr melden.
- Kein Changed Block Tracking. Die Zusatzsicherung arbeitet auf Dateiebene: eine geänderte Datei wird ganz gelesen, auch wenn sich nur ein Block änderte. Für große Datenbankdateien und VM-Abbilder ist das zu grob — dort braucht es CBT (PROMPT.md §8), das mit dem Proxmox-Provider in Phase 7 kommt. Abgelegt wird dank Deduplizierung dennoch nur der geänderte Teil.
- Keine VSS-Anbindung unter Windows: gesperrte Dateien wären derzeit nicht sicherbar.