Gentoo on ZFS encrypted root with EFI stub
ZFS file system is an interesting option for many Linux users and especially so for Gentoo users due to effortless snapshots and streamlined partition management. More recently added encrypted datasets also simplify file system encryption process, which applies with some caveats to a root mount encryption.
I don’t have a need for a conventional bootloader and always preferred
to use EFI stub kernel
with an EFI record. Setting up EFI stub loading for ZFS encrypted root
require zfs
kernel module to be available during the boot, this can
be solved either by doing a static ZFS install or by generating
initramfs
. The later option is preferable in my opinion due to
simpler kernel and ZFS upgrade process. You also need to make
encryption key available during the boot, there are multiple options
available for this including manually unlocking dataset by typing in a
passphrase. I opted to store encryption key on a tiny USB flash drive.
This post will contain necessary steps to reproduce my setup. I will intentionally not cover the Gentoo installation process onto ZFS. There are multiple guides available for this and process is pretty straightforward. The following overview will guide you through those options:
- Use installation media with ZFS to setup partitions then follow the
normal
stage3
and base system install. I would recommend Fearedbliss’s guide for this option. - Install Gentoo on non-ZFS partition, setup ZFS for the existing
installation and move install to a ZFS mount. If you are still
learning Gentoo you might want to gradually move to an encrypted
root. My personal path was Gentoo on
ext4
, then/home
on ZFS, then/root
on ZFS and finally/root
on ZFS encrypted dataset. To follow this path I recommend to read through the Gentoo’s Handbook and then ZFS Wiki page
The following text assumes that you have access to ZFS userland utilities and Gentoo’s base system.
Encryption key creation
As of now ZFS supports 3 key formats: passphrase
, hex
and
raw
. Depending on the key format key location can be prompt
or
absolute path to a key. The simplest option is to use passphrase
that will be typed in via prompt
on unlock, this is a bit tedious to
manage since you have to manually unlock your datasets on boot. This
could be improved by using hex
or raw
key located on another
partition, but this will require some protection to prevent access to
a key since it will be located next to an encrypted dataset. The
better option will be to use removable media as a key that will be
provided at the boot time as an absolute path to a raw device. This
will also allow you to remove the drive to prevent unlocking.
First we have to prepare partition on an USB drive that will contain our key data. As of now maximum supported key size is 512 bytes, so a single 1 sector partition should suffice. We have to offset partition by 2048 bytes which are reserved for GPT’s partition table.
$ parted -s /dev/sdX mklabel gpt mkpart key 2048s 2048s
Next we will write raw
key to this partition, we have to make sure
to exclude newline symbols to prevent undesirable key truncation as
described in this
comment.
$ tr -d '\n' < /dev/urandom | dd of=/dev/disk/by-partlabel/key
This will be enough for ZFS to create and unlock encrypted datasets using this removable drive.
Setting up ZFS encrypted mounts
Process for setting up ZFS encrypted datasets is not much different from the usual routine, we just have to provide 3 additional options:
$ zfs create -o encryption=on \
-o keyformat=passphrase \
-o keylocation=file:///dev/disk/by-id/usb-FK310-_128M_Mobile-Disk-part1 \
rpool/ROOT/gentoo
This command will enable aes-256-gcm
encryption for the provided
dataset with the passphare
key format and a key which is addressed
by the full absolute path to a raw device identified by it’s
id
. aes-256-gcm
encryption algorithm corresponds to the
AES
block cypher with 256 bits key size and the
GCM operation
mode, this is a strong and performant cypher and overall a great
default.
You can verify that encryption is applied to a dataset by doing:
$ zfs get encryption,keyformat,keylocation rpool/ROOT/gentoo
NAME PROPERTY VALUE
rpool/ROOT/gentoo encryption aes-256-gcm
rpool/ROOT/gentoo keyformat passphrase
rpool/ROOT/gentoo keylocation file:///dev/disk/by-id/usb-FK310-_128M_Mobile-Disk-part1
At this stage you can move your existing Gentoo installation to this
encrypted dataset. The next step is to make this root
mount visible
during the boot process.
Creating an EFI record
This section will describe how to create an EFI record that will be
able to boot your system using an encrypted root
dataset. The
following text assumes that you already have necessary kernel configs
enabled for the EFI stub per this wiki
page.
Since ZFS is most likely installed on your system as a kernel module
it won’t be included into your EFI stub, to fix that we need to create
an initramfs for our system
with a ZFS module in it. There multiple ways to create initramfs
, I
will use dracut below as I
found it easy to use and in most cases it will work without additional
settings.
Each time you upgrade and recompile your kernel you will also need to
create a new initramfs
image using the following command:
$ dracut -H --kver X.Y.Z-gentoo
-H
arguments stands for hostonly
, i.e. create an image
specifically for the local machine instead of generic. You should see
zfs
module in the dracut’s output and some help text about how to
enable ZFS on boot.
The next step is to copy initramfs
and EFI stub images to the
/boot
mount and create EFI record for it:
$ mv /boot/initramfs-X.Y.Z-gentoo.img /boot/efi/gentoo/initramfs-X.Y.Z.img
$ cp /usr/src/linux/arch/x86/boot/bzImage /boot/efi/gentoo/bzImage-X.Y.Z.efi
$ efibootmgr -c -d /dev/sdX -L "Gentoo X.Y.Z" \
-l '\EFI\Gentoo\bzImage-X.Y.Z.efi' \
-u 'initrd=\efi\gentoo\initramfs-X.Y.Z.img dozfs root=ZFS=rpool/ROOT/gentoo'
The above command will create a new EFI record with label Gentoo X.Y.Z
for the EFI stub image we generated, we will also pass
necessary arguments to the stub kernel so it would know where to find
initramfs
and how to activate ZFS for our root dataset.
At this stage you should be able to reboot and load back into the
system from the encrypted /root
mount. If something goes wrong you
should be able to see problems in the initramfs
output. In most
cases I would recommend to double check that initramfs
image has
zfs
module in it, your ZFS mounts point to the right place and key
is available during the boot.