Encrypting existing volumes in ZFS using zfs send and zfs recv

Let’s say you want to encrypt your previously not encrypted data – in my example a ZFS pool. A good way to do so is to simply use zfs send and zfs receive. These commands can be used to transfer ZFS data streams. The procedure is pretty simple. Create a snapshot, transfer this snapshot using zfs send and receive it using zfs receive.

However, if the parent of your target location is encrypted, e.g. tank/kvm/100 is encrypted and the target is tank/kvm/100/rootfs then this volume (rootfs) will NOT be encrypted. You can check this by issuing zfs get all tank/kvm/100/rootfs after you transfered the volume. You have to use -x to set the encryption on receive. If you use -o instead of -x:

~# zfs recv -o mountpoint=none -o encryption=aes-256-gcm -o keyformat=raw -o keylocation=... tank/kvm/100/rootfs

You’ll end up with the same key used twice in the system:

~# zfs load-key -a
2 / 2 key(s) successfully loaded

Also again if the parent (tank/kvm/100) is encrypted already and you are NOT using -o nor -x then zfs get all tank/kvm/100/rootfs will show you that no encryption will happen (if the source was not encrypted already). If you use -o then zfs get all will show that the properties are set local (not inherited). So in my case I have to use -x:

~# zfs recv -o mountpoint=none -x encryption -x keylocation -x keyformat tank/kvm/113/rootfs

This uses the encryption settings from the parent (inherit). So in case the parent is encrypted already you do NOT need to set the encryption options on zfs receive unless you want to use different / individual keys.

A full example

Here’s a full example, in my case 10.0.0.3 and 10.0.0.4 are a direct 1G connection between the two systems. There is no need to use “pv” you can just remove pv and remove the -q of mbuffer to see what’s happening.

Receiver

~# mbuffer -q -s 128k -m 1G -I 10.0.0.3:13371 | pv -bp | zfs recv -o mountpoint=none -x encryption -x keylocation -x keyformat tank/srv/mio/disk2-orig
24.4GiB [ <=> ]

Sender

~# zfs snapshot tank/srv/mio2/disk2@transfer
~# zfs send -c -L -R tank/srv/mio2/disk2@transfer | mbuffer -s 128k -m 1G -O 10.0.0.4:13371
in @ 0.0 kiB/s, out @ 111 MiB/s, 24.4 GiB total, buffer 3% full
summary: 24.4 GiByte in 3min 42.7sec - average of 112 MiB/s

Verify

~# zfs get all tank/srv/mio/disk2-orig
[..]
tank/srv/mio/disk2-orig encryption aes-256-gcm -
tank/srv/mio/disk2-orig keylocation none default
tank/srv/mio/disk2-orig keyformat raw -
tank/srv/mio/disk2-orig pbkdf2iters 0 default
tank/srv/mio/disk2-orig encryptionroot tank/srv/mio -
tank/srv/mio/disk2-orig keystatus available -

The encryption root is tank/srv/mio which means that the encryption stuff is inherited from it. Exactly what I want in this case.

By the way, zfs send and recv can be used on the same system; you don’t need to transfer it over the network. This should also work fine:

zfs send -c -L -R tank/srv/mio2/disk2-orig@transfer | zfs recv -o mountpoint=none -x encryption -x keylocation -x keyformat tank/srv/mio/disk2-new

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.