Installing Void Linux with encrypted Root on ZFS
Published on 03-01-2024 ( Updated 20-04-2024 )This guide is how I install Void Linux onto a single disk with with encrypted Root on ZFS and a seperate encrypted swap partition.
It assumes the following:
Your system uses UEFI to boot
Your system is x86_64
You will use glibc as your system libc.
You’re mildly comfortable with ZFS, EFI and discovering system facts on your own (lsblk, dmesg, gdisk, …)
ZFSBootMenu does not require glibc and is not restricted to x86_64. If you are comfortable installing Void Linux on other architectures or with the musl libc, you can adapt the instructions here to your desired configuration.
Please note that I have used information from the sources listed below:
ZFS BootMenu Docs https://docs.zfsbootmenu.org/en/v2.3.x/guides/void-linux/uefi.html
Void Linux ZFS Docs https://docs.voidlinux.org/installation/guides/zfs.html
Chain’s computar projects
https://forum.level1techs.com/t/chains-computar-projects/190001
Daniel Wayne Armstrong Blog
https://www.dwarmstrong.org/encrypt-swap/
To start
Download the latest hrmpf image from:
https://github.com/leahneukirchen/hrmpf
Write it to USB drive and boot your system in EFI mode.
Confirm EFI support:
# dmesg | grep -i efivars
[ 0.301784] Registered efivars operations
Configure Live Environment
Source /etc/os-release
The file /etc/os-release defines variables that describe the running distribution. In particular, the $ID variable defined within can be used as a short name for the filesystem that will hold this installation.
source /etc/os-release
export ID
Generate /etc/hostid
zgenhostid -f 0x00bab10c
Disk preparation
Verify your target disk devices with lsblk. /dev/sda
,
/dev/sdb
and /dev/nvme0n1
.
On my laptop
I,ll be using a single drive on /dev/nvme0n1
with three
paritions as follows:
1 - EFI boot 2 - Swap ( I’m using 64Gb but you can adjust to suit your needs or just not create swap and number the zpool parition 2 ) 3 - Zpool ( This partition uses the remaining disk space )
Note you will need to adjust below when wiping partitions if you use seperate disks.
Wipe partitions
zpool labelclear -f "/dev/nvme0n1"
wipefs -a "/dev/nvme0n1"
sgdisk --zap-all "/dev/nvme0n1"
Create EFI boot partition
sgdisk -n "1:1m:+512m" -t "1:ef00" "/dev/nvme0n1"
Create swap partition
sgdisk -n "2::64Gb" -t "2:8200" "/dev/nvme0n1" -c "2:cryptswap" "/dev/nvme0n1"
Create zpool partition
sgdisk -n "3:0:-10m" -t "3:bf00" "/dev/nvme0n1"
ZFS pool creation
Store the pool passphrase in a key file
echo 'SomeKeyphrase' > /etc/zfs/zroot.key
chmod 000 /etc/zfs/zroot.key
Create the encrypted zpool
zpool create -f -o ashift=12 \
-O compression=lz4 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O encryption=aes-256-gcm \
-O keylocation=file:///etc/zfs/zroot.key \
-O keyformat=passphrase \
-o autotrim=on \
-m none zroot "/dev/disk/by-id/wwn-0x5000c500deadbeef-part3"
Adjust the pool (-o) and filesystem (-O) options as desired, and
replace the partition identifier
wwn-0x5000c500deadbeef-part3
with that of the actual
partition to be used. You can find this out by typing
ls /dev/disk/by-id/
and they will be listed in the
output.
When adding disks or partitions to ZFS pools, it is generally advisable to refer to them by the symbolic links created in /dev/disk/by-id or (on UEFI systems) /dev/disk/by-partuuid so that ZFS will identify the right partitions even if disk naming should change at some point. Using traditional device nodes like /dev/sda3 may cause intermittent import failures. ## Create initial file systems
zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/${ID}
zfs create -o mountpoint=/home zroot/home
zpool set bootfs=zroot/ROOT/${ID} zroot
Note It is important to set the property
canmount=noauto
on any file systems withmountpoint=/
(that is, on any additional boot environments you create). Without this property, the OS will attempt to automount all ZFS file systems and fail when multiple file systems attempt to mount at/
; this will prevent your system from booting. Automatic mounting of/
is not required because the root file system is explicitly mounted in the boot process. Also note that, unlike many ZFS properties,canmount
is not inheritable. Therefore, settingcanmount=noauto
onzroot/ROOT
is not sufficient, as any subsequent boot environments you create will default tocanmount=on
. It is necessary to explicitly set thecanmount=noauto
on every boot environment you create.
Export,
then re-import with a temporary mountpoint of /mnt
zpool export zroot
zpool import -N -R /mnt zroot
zfs load-key -L prompt zroot
zfs mount zroot/ROOT/${ID}
zfs mount zroot/home
Verify that everything is mounted correctly
# mount | grep mnt
zroot/ROOT/void on /mnt type zfs (rw,relatime,xattr,posixacl)
zroot/home on /mnt/home type zfs (rw,relatime,xattr,posixacl)
Update device symlinks
udevadm trigger
Install Void
Adjust the mirror, libc, and package selection as you see fit.
XBPS_ARCH=x86_64 xbps-install \
-S -R https://mirrors.servercentral.com/voidlinux/current \
-r /mnt base-system
Copy our files into the new install
cp /etc/hostid /mnt/etc
mkdir /mnt/etc/zfs
cp /etc/zfs/zroot.key /mnt/etc/zfs
Chroot into the new OS
xchroot /mnt
Basic Void configuration
Set the keymap, timezone and hardware clock
cat << EOF >> /etc/rc.conf
KEYMAP="us"
HARDWARECLOCK="UTC"
TIMEZONE="Europe/London"
EOF
Configure your glibc locale
cat << EOF >> /etc/default/libc-locales
en_US.UTF-8 UTF-8
en_US ISO-8859-1
EOF
xbps-reconfigure -f glibc-locales
Set a root password
passwd
ZFS Configuration
Configure Dracut to load ZFS support
cat << EOF > /etc/dracut.conf.d/zol.conf
nofsck="yes"
add_dracutmodules+=" zfs "
omit_dracutmodules+=" btrfs resume "
install_items+=" /etc/zfs/zroot.key "
EOF
Install ZFS and Cryptsetup
xbps-install -S zfs cryptsetup
To quickly discover and import pools on boot, we need to set a pool cachefile
zpool set cachefile=/etc/zfs/zpool.cache zroot
Install and configure ZFSBootMenu
Set ZFSBootMenu properties on datasets
Assign command-line arguments to be used when booting the final kernel. Because ZFS properties are inherited, assign the common properties to the ROOT dataset so all children will inherit common arguments by default.
zfs set org.zfsbootmenu:commandline="quiet loglevel=4" zroot/ROOT
Setup key caching in ZFSBootMenu.
zfs set org.zfsbootmenu:keysource="zroot/ROOT/${ID}" zroot
Create
vfat
and encrypted swap
filesystems
mkfs.vfat -F32 /dev/nvme0n1p1
cat << EOF >> /etc/crypttab
cryptswap /dev/disk/by-partlabel/cryptswap /dev/urandom swap,offset=2048,cipher=aes-xts-plain64,size=512
EOF
Create fstab entries and mount the efi partition
cat << EOF >> /etc/fstab
$( blkid | grep /dev/nvme0n1p1 | cut -d ' ' -f 2 ) /boot/efi vfat defaults 0 0
/dev/mapper/cryptswap none swap defaults 0 0
EOF
mkdir -p /boot/efi
mount /boot/efi
Install ZFSBootMenu
xbps-install -S zfsbootmenu systemd-boot-efistub
Configure generate-zbm(5) by ensuring that the following keys appear in /etc/zfsbootmenu/config.yaml:
Global:
ManageImages: true
BootMountPoint: /boot/efi
Components:
Enabled: false
EFI:
ImageDir: /boot/efi/EFI/zbm
Versions: false
Enabled: true
Kernel:
CommandLine: quiet loglevel=0
My CommandLine:
will be as follows as I don’t want
ZFSBootMenu automatically resizing the fonts according to the display
size.
CommandLine: quiet loglevel=0 zbm.skip_hooks=20-console-autosize.sh
Create a ZFSBootMenu image:
generate-zbm
Configure EFI boot entries
xbps-install efibootmgr
efibootmgr -c -d "/dev/nvme0n1" -p "1" \
-L "ZFSBootMenu (Backup)" \
-l '\EFI\ZBM\VMLINUZ-BACKUP.EFI'
efibootmgr -c -d "/dev/nvme0n1" -p "1" \
-L "ZFSBootMenu" \
-l '\EFI\ZBM\VMLINUZ.EFI'
Prepare for first boot
Exit the chroot, unmount everything
exit
umount -n -R /mnt
Export the zpool and reboot
zpool export zroot
reboot