How to enable, and then migrate to, native ZFS encryption in Proxmox
·2 mins
Introduction #
My use case:
- Add encryption-at-rest to an existing unencrypted Proxmox host.
- Encryption only for LXC and VM data. None for the root installation.
- Automatic decryption on server startup (and not requiring me to enter any encryption key).
It took me awhile to figure everything out but eventually, as with most ZFS stuff, things turned out fairly straightforward.
Pre-requisites #
Verify the machine supports hardware acceleration. (It most probably would but doesn’t harm to verify.) This is what GPT-4 recommended for my Intel machine:
grep aes /proc/cpuinfo
.lsmod | grep aesni
.
Initial setup #
# Create an encryption key.
od -Anone -x -N 32 -w64 /dev/random | tr -d [:blank:] > /root/crypt.key
# Create an encrypted "child" dataset. Then, import it into Proxmox by adding a new "Storage".
zfs create -o encryption=on -o keyformat=hex -o keylocation=file:///root/crypt.key fast-zfs-pool/crypt
# Verify.
zfs get encryption
zfs get keylocation fast-zfs-pool/crypt
For automatic decryption on machine startup, add the following to the /etc/systemd/system/zfs-load-keys.service file:
[Unit]
Description=Load encryption keys
DefaultDependencies=no
After=zfs-import.target
Before=zfs-mount.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/zfs load-key -a
StandardInput=tty-force
[Install]
WantedBy=zfs-mount.service
And then enable and verify the service by running:
systemctl enable zfs-load-keys.service
systemctl status zfs-load-keys.service
That’s it!
Migration #
One way is to migrate through the Proxmox UI but I encountered 2 issues with that.
- Proxmox wants the LXCs/VMs to be shutdown during the migration and that can be quite awhile depending on the volume size.
- In some cases, the post-encryption volume size can be as high as twice the original, probably because ZFS couldn’t compress as much as before. Proxmox then throws (unhelpful) errors instead of just hinting that the volume should first be resized.
My approach is the following, in order:
- Create a ZFS snapshot of a volume.
- ZFS send+receive the snapshot to the new dataset.
- Shut down the LXC/VM.
- If you absolutely care about the most up to date data, something I did only for one LXC, create a new snapshot and do an incremental send (using
zfs send -i
). - Update
refquota
if it’s an LXC volume, otherwise Proxmox wouldn’t show the right size on the UI. - Update LXC/VM config in /etc/pve/ and then start it.
# Create snapshot
zfs snapshot fast-zfs-pool/subvol-100-disk-0@2024-11-18
zfs list -t snapshot
# Send it to the new dataset.
zfs send fast-zfs-pool/subvol-100-disk-0@2024-11-18 | zfs recv -F fast-zfs-pool/crypt/subvol-100-disk-0@2024-11-18
# Update "refquota".
zfs set refquota=64G fast-zfs-pool/crypt/subvol-100-disk-0
# Cleanup
zfs destroy fast-zfs-pool/subvol-100-disk-0@2024-11-18