Zum Inhalt

Kryptografisch deduplizierte Backups: BorgBackup, Borgmatic, Append-Only SSH & 3-2-1-1-0 Wiederherstellung

Erstellt: 06.11.2026 Aktualisiert: 06.11.2026

Management Summary: Sich ausschließlich auf RAID-Verbünde oder einfache rsync-Skripte zu verlassen, lässt Systeme schutzlos gegen Ransomware, Dateisystem-Bit-Rot oder unabsichtliches rm -rf. Diese Referenzarchitektur beschreibt den Einsatz von BorgBackup in Kombination mit Borgmatic. Der Leitfaden behandelt inhaltsbasierte Buzhash-Chunk-Deduplizierung, authentifizierte AEAD AES-256-OCB / BLAKE2b Client-Verschlüsselung, atomare Datenbank-Dumps im Stream sowie Append-Only (--append-only) SSH-Restriktionen, um unveränderliche, manipulationssichere Off-Site-Backups zu garantieren.

  • Buzhash Variable Chunk-Deduplizierung


    Teilt Dateien über ein rollendes Hash-Fenster dynamisch auf, sodass Umbenennungen oder Anhänge an große VM-Images nur minimalen neuen Speicherplatz belegen.

  • repokey-blake2 AEAD-Verschlüsselung


    Verschlüsselt Datenblöcke, Dateinamen und Metadaten clientseitig, bevor ein einziges Byte das System verlässt – der Remote-Server arbeitet nach dem Zero-Knowledge-Prinzip.

  • Unveränderliches Append-Only SSH-Target


    Beschränkt den SSH-Schlüssel des Clients auf command="borg serve --append-only", sodass selbst ein kompromittierter Produktivserver historische Archive nicht löschen kann.

  • Deklarative Borgmatic-Pipelines


    Automatisiert gestreamte pg_dump/mariadb-dump-Hooks, GFS-Aufbewahrungsfristen (keep_daily/keep_monthly) und kryptografische borg check-Prüfungen in einer YAML-Datei.


1. Architektur: Buzhash-Chunking, Client-AEAD & Append-Only Speicher

Verarbeitet BorgBackup ein Verzeichnis, vertraut es nicht allein Zeitstempeln: Es schiebt Daten durch ein Buzhash-Rolling-Window und teilt Datenströme in variable Blöcke ($64\text{ KiB}$ bis $4\text{ MiB}$). Jeder Block wird mit einem Keyed MAC verifiziert, komprimiert (zstd) und clientseitig verschlüsselt:

%%{init: {'flowchart': {'wrappingWidth': 600, 'subGraphTitleMargin': {'top': 15, 'bottom': 15}}}}%%
flowchart TB
    subgraph SourceHost["Produktiv-Host (Borgmatic + Borg Client)"]
        DBHook["Borgmatic Pre-Hook<br/>Streaming pg_dump / MariaDB"]
        Buzhash["Buzhash Rolling Chunker<br/>Deduplizierungs-Index"]
        Crypto["zstd-6 Kompression +<br/>repokey-blake2 Verschlüsselung"]
    end

    subgraph UntrustedSSH["SSH-Transport (Port 22)"]
        SSHStream["Verschlüsselte SSH-Pipe<br/>Zero Server-Side Plaintext"]
    end

    subgraph BackupVault["Off-Site Storage Vault (Borg Server)"]
        AuthKeys["SSH authorized_keys<br/>borg serve --append-only"]
        Repo[("Unveränderliches Borg Repository<br/>Transaktions-Log Segmente")]
    end

    DBHook -->|"Stdout Pipe"| Buzhash
    Buzhash -->|"Nur neue Chunks"| Crypto
    Crypto --> SSHStream
    SSHStream --> AuthKeys
    AuthKeys -->|"Ausschließlich anhängen"| Repo

Warum der Append-Only-Modus Ransomware wirkungslos macht

Erlangen Angreifer Root-Rechte auf dem Produktivserver, finden sie den SSH-Schlüssel und die Passphrase des Backup-Repositories. Auf einem Standard-SSH-Server könnten sie sofort borg delete oder rm -rf ausführen, um alle Backups vor der Verschlüsselung zu vernichten.

Erzwingt der Remote-Server in ~/.ssh/authorized_keys jedoch die Direktive command="borg serve --append-only --restrict-to-path /srv/borg/prod-node", wandelt borg serve Lösch- und Pruning-Befehle serverseitig in nicht-destruktive Transaktionsmarkierungen um. Alle historischen Segmente bleiben unverändert auf dem Dateisystem erhalten.


2. Remote-Backup-Server härten (--append-only)

Legen Sie auf dem Backup-Server einen dedizierten Benutzer borg an und hinterlegen Sie den öffentlichen SSH-Schlüssel mit strenger Restriktion:

/srv/borg/.ssh/authorized_keys (Auf dem Remote-Backup-Server)
command="borg serve --append-only --restrict-to-path /srv/borg/repos/prod-node-01",restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... root@prod-node-01

Initialisieren Sie das Repository vom Produktivhost aus und exportieren Sie den Repository-Schlüssel zwingend offline:

Borg-Repository initialisieren & Notfall-Schlüssel sichern
export BORG_PASSPHRASE="Ihr-Sehr-Sicheres-64-Zeichen-Passwort"

# 1. Verschlüsseltes Repository über SSH initialisieren
borg init --encryption=repokey-blake2 ssh://borg@vault.nejat-hakan.de:22/srv/borg/repos/prod-node-01

# 2. PFLICHT: Schlüssel exportieren und im Passwort-Manager sowie ausgedruckt hinterlegen!
borg key export ssh://borg@vault.nejat-hakan.de:22/srv/borg/repos/prod-node-01 ~/borg-prod-node-01-key-backup.txt
borg key export --paper ssh://borg@vault.nejat-hakan.de:22/srv/borg/repos/prod-node-01 ~/borg-prod-node-01-paper.txt

Ohne Schlüsseldatei UND Passphrase ist keine Wiederherstellung möglich

Geht bei einem Hardware-Totalausfall der Repository-Header verloren, bedeutet das Fehlen des exportierten Keys den unwiderruflichen Verlust aller Daten. Sichern Sie den Papierschlüssel stets an einem separaten physischen Ort (3-2-1-1-0-Regel).


3. Deklarative Borgmatic-Konfiguration (/etc/borgmatic/config.yaml)

Definieren Sie Quellverzeichnisse, Datenbank-Streaming-Hooks, Retention-Policys und Integritätsprüfungen übersichtlich in einer YAML-Datei (chmod 0600):

/etc/borgmatic/config.yaml
source_directories:
  - /etc
  - /opt
  - /var/vmail
  - /home

repositories:
  - path: ssh://borg@vault.nejat-hakan.de:22/srv/borg/repos/prod-node-01
    label: offsite_vault
  - path: /mnt/local_zfs_backup/borg/prod-node-01
    label: local_zfs

exclude_patterns:
  - "*.pyc"
  - "*/.cache/*"
  - "/var/lib/docker/overlay2/*"
  - "/opt/*/data/logs/*"
exclude_caches: true
exclude_if_present:
  - .nobackup

# --- Kompression & Verschlüsselung ---
compression: auto,zstd,6
encryption_passcommand: "cat /etc/borgmatic/.borg_passphrase"
archive_name_format: "{hostname}-{now:%Y-%m-%dT%H:%M:%S}"
ssh_command: "ssh -i /root/.ssh/id_ed25519_borg -o StrictHostKeyChecking=accept-new"

# --- Grandfather-Father-Son (GFS) Aufbewahrung ---
keep_hourly: 24
keep_daily: 14
keep_weekly: 8
keep_monthly: 12
keep_yearly: 3

# --- Regelmäßige Konsistenzprüfungen ---
checks:
  - name: repository
    frequency: 1 week
  - name: archives
    frequency: 2 weeks
  - name: data
    frequency: 1 month
    max_duration: 3600

# --- Datenbank-Streaming im RAM (Keine Zwischendateien auf Platte) ---
postgresql_databases:
  - name: all
    hostname: 127.0.0.1
    port: 5432
    username: postgres
    format: custom

mariadb_databases:
  - name: all
    hostname: 127.0.0.1
    username: root
    password: "${MARIADB_ROOT_PASSWORD}"
    options: "--single-transaction --quick"

# --- Dead-Man's-Switch Überwachung via Uptime Kuma ---
uptime_kuma:
  push_url: "https://status.nejat-hakan.de/api/push/x9Km2pL8qR"
  states:
    - start
    - finish
    - fail

4. Verifikation, FUSE-Mounting & Wiederherstellungsübung

Ein Backup ist nur so verlässlich wie der verifizierte Restore-Test. Borg erlaubt es, jedes historische Archiv als schreibgeschütztes FUSE-Dateisystem (borg mount) einzuhängen:

Borgmatic ausführen & FUSE-Restore testen
# 1. Konfigurationssyntax prüfen
sudo borgmatic config validate

# 2. Vollständigen Backup-Durchlauf mit Statistiken starten
sudo borgmatic --verbosity 1 --stats

# 3. Vorhandene Archive auflisten und Deduplizierungsrate ansehen
sudo borgmatic list
sudo borgmatic info --archive latest

# 4. Neuestes Archiv als FUSE-Dateisystem einbinden und prüfen
sudo mkdir -p /mnt/borg-restore
sudo borgmatic mount --archive latest --mount-point /mnt/borg-restore
ls -la /mnt/borg-restore/etc
sudo borgmatic umount --mount-point /mnt/borg-restore