- Abraxas - https://www.effinger.org -

TrueNAS Backup mit zrep

TrueNAS bietet zwar von sich aus eine Backup-Lösung an, allerdings geht die Initiierung des Backups immer vom Server mit den Daten aus, der dann zum Backup-Server repliziert. Aus Sicherheitsaspekten ist dies nicht optimal, denn wenn der Datenserver kompromittiert ist, besteht auch die Gefahr, dass der Backup-Server oder die Backups verändert werden. Aus diesem Grund habe ich mich dazu entschlossen, selbst eine Backup-Lösung mit zrep zu implementieren. Diese sieht folgendermaßen aus:

  1. Der Backup-Server greift über ssh auf den Datenserver zu. Dabei wird ein Benutzer verwendet, der nur eingeschränkte Rechte auf dem Daten- und Backupserver hat
  2. Der Backup-Server legt mit zrep einen Snapshot auf den zu sichernden ZFS Pools des Datenservers an und kopiert diese dann auf den ZFS Pool auf dem Backup-Server
  3. Der Backup-Server löscht in regelmäßigen Abständen nicht mehr benötigte Snapshots auf dem Backup-Server
  4. Der Daten-Server löscht in regelmäßigen Abständen nicht mehr benötigte Snapshots auf dem Daten-Server

In TrueNAS wird im GUI unter Storage/Pools zunächst ein Dataset für den Benutzer zsbackup (s für send) angelegt (hier: /mnt/data0/zsbackup) und dann der Benutzer:

[1]

Über die Shell geben wir dem Benutzer nun die erforderlichen Rechte, laden das zrep Skript herunter und machen es ausführbar

zfs allow -u zsbackup send,hold,snapshot,userprop data0
cd /mnt/data0/zsbackup
wget https://github.com/bolthole/zrep/raw/master/zrep
chmod +x zrep

Auf dem Backup-Server machen wir das analog:

[2]

und führen auch hier die folgenden Befehle aus:

zfs allow -u zrbackup create,mount,receive,userprop remote_backup
cd /mnt/remote_backup/zrbackup
wget https://github.com/bolthole/zrep/raw/master/zrep
chmod +x zrep

SSH-Keys erzeugen

Im nächsten Schritt müssen wir dafür sorgen, dass zrbackup sich auf dem Datenserver als zsbackup mittels ssh einloggen kann. Dazu erzeugen wir auf dem Backup-Server den ssh-key:

su zrbackup
ssh-keygen -t rsa -b 4096

Wichtig hier ist, dass alles mit Enter bestätigt wird und kein Passwort vergeben wird. Dann legen wir auf dem Datenserver das .ssh-Verzeichnis an und ergänzen den öffentlichen Key in der Datei authorized_keys hinterlegen

su zsbackup
mkdir /mnt/data0/zsbackup/.ssh
vi /mnt/data0/zsbackup/.ssh/authorized_keys

Statt mit dem Editor zu arbeiten kann man vom Backup-Server mittels root-login auch den Schlüssel wie folgt hinterlegen:

<.ssh/id_rsa.pub ssh root@dataserver 'cat >> /mnt/data0/zsbackup/.ssh/authorized_keys'

Dann sollte man vom Backup-Server den Login testen mittels

ssh zsbackup@dataserver

Erstes Backup manuell erzeugen

Wenn man noch keinen Backup-Pool hat, sondern komplett neu anfängt, kann man sich an die zrep-Anleitung halten und von Grund auf einen Backup-Pool erzeugen. Da ich jedoch bereits einen Pool mit Backup-Snapshots habe, bin ich wie folgt vorgegangen, um diesen Pool auch mit zrep zu nutzen.

Im ersten Schritt wird ein Snapshot in der zrep-Nomenklatur erzeugt und dann die entsprechende zrep-Konfiguration hinterlegt.

zsbackup@dataserver$ zfs snap data0/pool1@zrep_000001
zsbackup@dataserver$ ./zrep changeconfig -f data0/pool1 backupserver remote_backup/pool1

Anschließend kann man mit folgenden Befehlen manuell über zfs send/receive diesen Snapshot auf den backupserver übertragen und zwar vom Backupserver aus (last_synced_snapshot durch den Snapshot ersetzen, der auf beiden Systemen vorhanden ist).

zrbackup@backupserver$ ssh -p 22 -l zsbackup dataserver zfs send -I data0/pool1@last_synced_snapshot data0/pool1@zrep_000001 | zfs recv -F remote_backup/pool1

Nun kann man auch auf dem Backup-Server auch die zrep-Konfiguration ergänzen

zrbackup@backupserver$ ./zrep changeconfig -f -d remote_backup/pool1 dataserver data0/pool1

Jetzt noch auf dem Datenserver das „master“ flag setzen und zrep mitteilen, dass der letzte Sync schon erfolgt ist mittels

zsbackup@dataserver$ ./zrep sentsync -L data0/pool1@zrep_000001

Überprüfen lassen sich die im zfs pool als properties hinterlegten Konfigurationen mittels

zsbackup@dataserver$ ./zrep list -v data0/pool1
zrbackup@backupserver$ ./zrep list -v remote_backup/pool1

Backup mit zrep testen

Folgender Befehl auf dem Backup-Server sollte nun erfolgreich ausgeführt werden können

zrbackup@backupserver$ env SSH="ssh -p 22 -l zsbackup" ZREP_SKIP_EXPIRE=1 ZREP_PATH="/mnt/data0/zsbackup/zrep" /mnt/remote_backup/zsbackup/zrep refresh remote_backup/pool1

Übrigens habe ich in allen Befehlen explizit den Port 22 angegeben. Das wäre nicht notwendig, aber wenn man SSH nicht auf dem Standardport laufen lässt, kann man 22 einfach ändern in den passenden Port.

Cronjobs anlegen

Nun können wir einen Cronjob anlegen – entweder direkt mit dem Befehl zum Testen oder aber über ein eigenes Skript, das den obigen Befehl enthält und z.B. so aussehen kann

#!/bin/bash
# Skript to pull backups of different datasets from dataserver
env SSH="ssh -p 22 -l zsbackup" ZREP_PATH="/mnt/data0/zsbackup/zrep" ZREP_SKIP_EXPIRE=1 /mnt/remote_backup/zrbackup/zrep refresh remote_backup/pool1
env SSH="ssh -p 22 -l zsbackup" ZREP_PATH="/mnt/data0/zsbackup/zrep" ZREP_SKIP_EXPIRE=1 /mnt/remote_backup/zrbackup/zrep refresh remote_backup/pool2
env SSH="ssh -p 22 -l zsbackup" ZREP_PATH="/mnt/data0/zsbackup/zrep" ZREP_SKIP_EXPIRE=1 /mnt/remote_backup/zrbackup/zrep refresh remote_backup/pool3

Im TrueNAS GUI auf dem Backup-Server legen wir dann den Cronjob an:

[3]

Cronjobs, um alte Snapshots zu löschen

Die Berechtigung zum Löschen von Snapshots haben sowohl der zrbackup als auch der zsbackup user nicht auf den Servern, denn leider könnten diese mit der entsprechenden Berechtigung destroy sogar das komplette dataset löschen [4]. Aus diesem Grund werden alte zrep Snapshots über einen separaten Cronjob gelöscht, der root-Rechte besitzt und dessen Befehl auf dem Backup-Server wie folgt aussieht:

/mnt/remote_backup/zrbackup/zrep expire -L remote_backup/pool1

Auch auf dem Datenserver legen wir auch einen entsprechenden Cronjob an

/mnt/remote_backup/zsbackup/zrep expire -L data0/pool1

Ein interessantes und noch flexibleres Tool für diese Aufgabe ist zrep-expire [5]. Inspiriert zu diesem Vorgehen hat mich auch der Blog-Post Improving Replication Security With OpenZFS Delegation [6]