Mein Datenhaufen zu IT und Elektronik Themen.

Schlagwort: Jail

FreeBSD 13 unverschlüsseltes ZFS Dataset/Jail zu verschlüsseltem ZFS Dataset/Jail

Mit FreeBSD 13 lässt sich die native ZFS Verschlüsselung direkt nutzen. Dabei muss man zwischen einem komplett verschlüsselten zpool und verschlüsselten Datasets unterscheiden. Hat man einen komplett verschlüsselten zpool, bedeutet es nicht, dass damit auch alle Datasets verschlüsselt sein müssen, so wie es auch nicht bedeutet, dass man Datasets nur verschlüsseln kann, wenn auch der komplette ZFS Pool verschlüsselt ist.

Wer nun also sein FreeBSD auf Version 13 gehoben hat, möchte ggf. einzelne ZFS Datasets verschlüsseln. In der Praxis trifft dieses sicher oft auf Jails zu. Diese liegen in der Regel in eigenen ZFS Datasets und mit dem folgenden Beispiel lassen sich diese und andere Datasets nachträglich verschlüsseln.

Im Beispiel haben wir den Pool zroot und in diesem das Dataset varta. Weder der zpool noch das Dataset sind aktuell verschlüsselt:

root@testtest:/ # zfs list zroot/varta
NAME          USED  AVAIL     REFER  MOUNTPOINT
zroot/varta   100M  12.0G      100M  /zroot/varta
root@testtest:/ # zfs get encryption zroot/varta
NAME         PROPERTY    VALUE        SOURCE
zroot/varta  encryption  off          default
root@testtest:/ #

Aktiviert man bei ZFS Dinge wie Komprimierung oder Deduplikation sind diese immer nur ab dem Moment der Aktivierung und bis genau zur Deaktivierung aktiv. Dieses hat viele Vorteile aber auch Nachteile. So greift dieses nur für Daten, welche neu geschrieben werden. Möchte man dieses nachträglich auf alle Daten anwenden, muss man die Daten komplett neu schreiben. Dieses lässt sich am einfachsten und schnellsten per zfs send und zfs receive erledigen. Wenn man also sein bestehendes Dataset verschlüsseln möchte, dann geht dieses faktisch nicht, sondern man erstellt im Grunde ein neues verschlüsseltes Dataset und schreibt seine Daten dort rein.

Bevor wir nun mit der Migration starten, müssen wir noch eine Kleinigkeit wissen…. Zum Verschlüsseln der Daten benötigen wir noch ein Geheimnis, einen Schlüssel/Key. Dieser kann bei ZFS in verschiedenster Form und an verschiedensten Orten liegen. So könnte man den Key zur Ver- und Entschlüsselung auf einen USB-Stick ablegen. Nur wenn dieser auch im System steckt usw. usw.. Der eingängigste Weg ist sicher ein Passphrase welches per prompt abgefragt wird. Will man sein verschlüsseltes Dataset öffnen, wird man nach einem Kennwort gefragt, welches sich das System bis zum nächsten Reboot oder dem manuellen „Schließen“ des Datasets merkt. Diesen Zustand wollen wir nach der Migration, in diesem Beispiel, erreichen.

Zur Verdeutlichung erstellen wir kurz ein neues verschlüsseltes Dataset:

root@testtest:/ # zfs create -o encryption=on -o keyformat=passphrase -o keylocation=prompt zroot/enc-beispiel
Enter passphrase:
Re-enter passphrase:

Damit haben wir ein neues Dataset welches sofort benutzt werden kann, alles was wir in dieses legen, ist verschlüsselt.

root@testtest:/ # zfs list zroot/enc-beispiel
NAME                 USED  AVAIL     REFER  MOUNTPOINT
zroot/enc-beispiel   200K  12.0G      200K  /zroot/enc-beispiel

Schauen wir in die Optionen des Datasets ist die Verschlüsselung aktiviert und der Schlüssel wird per Prompt vom Benutzer abgefragt:

root@testtest:/ # zfs get encryption,keylocation,keyformat zroot/enc-beispiel
NAME                PROPERTY     VALUE        SOURCE
zroot/enc-beispiel  encryption   aes-256-gcm  -
zroot/enc-beispiel  keylocation  prompt       local
zroot/enc-beispiel  keyformat    passphrase   -

Wie immer wird das Dataset sofort eingehangen:

root@testtest:/ # mount |grep enc-beispiel
zroot/enc-beispiel on /zroot/enc-beispiel (zfs, local, noatime, nfsv4acls)

Nach einem reboot, wird das Dataset nicht automatisch eingehangen, da ZFS den Schlüssel nicht hat. Wenn wir es nun einhängen und ZFS anweisen, den Schlüssel zu laden (Option -l), dann werden wir zur Eingabe des Kennwortes aufgefordert und können das Dataset im Anschluss wieder nutzen:

root@testtest:~ # mount | grep enc-beispiel
root@testtest:~ # zfs get encryption,keylocation,keyformat zroot/enc-beispiel
NAME                PROPERTY     VALUE        SOURCE
zroot/enc-beispiel  encryption   aes-256-gcm  -
zroot/enc-beispiel  keylocation  prompt       local
zroot/enc-beispiel  keyformat    passphrase   -
root@testtest:~ # mount | grep enc-beispiel
root@testtest:~ # zfs mount -l zroot/enc-beispiel
Enter passphrase for 'zroot/enc-beispiel':
root@testtest:~ # mount | grep enc-beispiel
zroot/enc-beispiel on /zroot/enc-beispiel (zfs, local, noatime, nfsv4acls)

Gut gut… So viel zu den Basics. Damit ist nun auch klar, warum im nun folgenden zfs send / zfs reveive Beispiel, der Schlüssel einen Umweg nehmen wird. Denn durch das pipen kommen wir so schlecht an die stdin heran, um das Passphrase einzugeben 😉 Wir sind nun also wieder zurück bei unserem unverschlüsselten Dataset varta und dessen Migration in einen verschlüsselten Zustand. Als erstes legen wir nun das gewünschte Passphrase in einer Datei ab:

root@testtest:~ # echo 'Tolles-Kennwort' > /kennwort.txt
root@testtest:~ # cat /kennwort.txt 
Tolles-Kennwort

Ebenfalls erstellen wir einen snapshot vom Dataset varta, welchen wir zur Migration nutzen:

root@testtest:~ # zfs snapshot zroot/varta@migration
root@testtest:~ # zfs list -t snapshot
NAME                    USED  AVAIL     REFER  MOUNTPOINT
zroot/varta@migration     0B      -      100M  -

Jetzt kann die eigentliche Migration starten:

root@testtest:~ # zfs send zroot/varta@migration | zfs receive -F -o encryption=on -o keyformat=passphrase -o keylocation=file:///kennwort.txt zroot/en-varta
root@testtest:~ # zfs list zroot/varta zroot/en-varta
NAME             USED  AVAIL     REFER  MOUNTPOINT
zroot/en-varta   100M  11.8G      100M  /zroot/en-varta
zroot/varta      100M  11.8G      100M  /zroot/varta
root@testtest:~ # zfs list -t snapshot
NAME                       USED  AVAIL     REFER  MOUNTPOINT
zroot/en-varta@migration   112K      -      100M  -
zroot/varta@migration        0B      -      100M  -

Das ist schnell und einfach, oder? Natürlich liegt nun noch immer das Passphrase offen in einer Datei im root des Systems. Wir müssen nun also den Ort des Schlüssels auf prompt ändern:

root@testtest:~ # zfs get keylocation zroot/en-varta
NAME            PROPERTY     VALUE                 SOURCE
zroot/en-varta  keylocation  file:///kennwort.txt  local
root@testtest:~ # zfs set keylocation=prompt zroot/en-varta
root@testtest:~ # zfs get keylocation zroot/en-varta
NAME            PROPERTY     VALUE        SOURCE
zroot/en-varta  keylocation  prompt       local

Damit kann die Datei mit dem Passphrase gelöscht werden:

root@testtest:~ # rm /kennwort.txt

Ebenfalls kann nun auch das unverschlüsselte Dataset weg:

root@testtest:~ # zfs destroy -r zroot/varta

Wenn man nun möchte, kann man das neue Dataset natürlich an die gleiche Stelle mounten oder direkt komplett gleich dem alten benennen:

root@testtest:~ # zfs rename zroot/en-varta zroot/varta

Damit ist die Migration fertig und das Dataset ist verschlüsselt:

root@testtest:~ # zfs list zroot/varta
NAME          USED  AVAIL     REFER  MOUNTPOINT
zroot/varta   100M  11.9G      100M  /zroot/varta
root@testtest:~ # zfs get encryption,keylocation,keyformat zroot/varta
NAME         PROPERTY     VALUE        SOURCE
zroot/varta  encryption   aes-256-gcm  -
zroot/varta  keylocation  prompt       local
zroot/varta  keyformat    passphrase   -

Es sieht nun nach sehr viel aus, ist es aber nicht und es lässt sich sogar automatisieren.

Fragen? Dann fragen!

zfs send / recv schlägt mit „cannot receive incremental stream: destination […] has been modified“ fehl

Tach auch… Heute mal wieder etwas zum Thema ZFS (anscheinend wohl im Moment gefragt…)

Wenn man ZFS Volumes abgleichen möchte hilft einem bekanntermaßen ja zfs send / revc. Möchte man noch eine gewisse Historie am Ziel oder es handelt sich um recht große Volumes, dann freut man sich sehr über die Möglichkeit nur die Differenz zwischen zwei Snapshots abgleichen zu müssen.

Als kleines Beispiel:

Ich habe eine FreeBSD Jail für subsonic. In dieser liegen einfach die gesamten Mediafiles, was weiß ich.. Sagen wir mal 100GB. Vom Volume werden dann automatisch per zfsutils snapshots erstellt. Die wöchentlichen snapshots davon möchte ich nun gerne per SSH auf ein anderes System schieben, einfach um die Daten so „gesichert“ zu haben. Jedes System steht dann vielleicht noch in der Colocation in einem anderen DataCenter. Einmal die Woche 100GB abgleichen, das sind dann im Monat 400GB (ja, viel ist anders aber es ist ein reales Beispiel).

Initial pumpt das Skript nun also die 100GB rüber. Ich schreib mal den Befehl ohne Variablen zur besseren Lesbarkeit, ok?

zfssend@system01:~ # zfs send zroot/jails/subsonic@zfs-auto-snap_weekly-2015-06-14-00h14 | ssh zfsrecv@system02 zfs recv zroot/backup/bsd02/subsonic

So jetzt habe ich also auf der zweiten Kiste eine 1a Kopie der Jail. Ab dem Moment muss ich nun nur noch die Differenz zum nächsten Snapshot übertragen mit einem:

zfssend@system01:~ # zfs send -i zroot/jails/subsonic@zfs-auto-snap_weekly-2017-03-12-00h14 zroot/jails/subsonic@zfs-auto-snap_weekly-2017-03-19-00h14 | ssh zfsrecv@system02 zfs recv zroot/backup/bsd02/subsonic

Dieses funktioniert natürlich nur so lange die Daten im Ziel nicht verändert werden. Klar wie bei jeder Datensicherung die auf Inkrementen beruht. Ändere ich eines sind die nachfolgenden nicht mehr konsistent. Wie könnte nun so eine Änderung passieren? Ganz einfach ich renne in dem Filesystem herum und ändere Daten oder lege neue an. Was viele übersehen ist etwas wie atime. Also das einfache speichern der Information: Wann wurde die Datei zuletzt angefasst. Dieses würde schon als Änderung reichen um folgendes zu bekommen:

zfssend@system01:~ # zfs send -i zroot/jails/subsonic@zfs-auto-snap_weekly-2017-03-12-00h14 zroot/jails/subsonic@zfs-auto-snap_weekly-2017-03-19-00h14 | ssh zfsrecv@system02 zfs recv zroot/backup/bsd02/subsonic
cannot receive incremental stream: destination zroot/backup/bsd02/subsonic has been modified
since most recent snapshot
warning: cannot send 'zroot/jails/subsonic@zfs-auto-snap_weekly-2017-03-19-00h14': signal received

Und nun ist Essig mit der schönen Sicherung und man muss wieder Initial alles rüber schieben? Jain… Natürlich kann man dem zfs recv einfach mitteilen die Änderung zu ignorieren. Denn der snapshot ist dem Ziel ja bekannt. Also kann man dem Ziel sagen: der bestehende snapshot zählt, ignoriere als was danach passiert ist und gleiche das Delta zum aktuellen ab:

zfssend@system01:~ # zfs send -i zroot/jails/subsonic@zfs-auto-snap_weekly-2017-03-12-00h14 zroot/jails/subsonic@zfs-auto-snap_weekly-2017-03-19-00h14 | ssh zfsrecv@system02 zfs recv -F zroot/backup/bsd02/subsonci

Ein -F ist hier also unser Freund. Hat man alles sauber geskriptet und ebenfalls nicht vergessen im Ziel hin und wieder die alten snapshots aufzuräumen, sollte man damit schon eine ganz brauchbare Datensicherheit haben!

Viel Spaß!

© 2024 -=Kernel-Error=-

Theme von Anders NorénHoch ↑