Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Epic Ubuntu ZFS Setup #146

Open
wants to merge 46 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
569f850
Epic Ubuntu ZFS Setup
TommyTran732 Jul 26, 2023
9407450
Minor fixes
TommyTran732 Jul 26, 2023
748b309
Fix
TommyTran732 Jul 26, 2023
b617042
Epic
TommyTran732 Jul 26, 2023
83b92ae
Update
TommyTran732 Jul 26, 2023
e8b62e2
Update
TommyTran732 Jul 26, 2023
3cdaf86
Update
TommyTran732 Jul 26, 2023
e399604
Update
TommyTran732 Jul 26, 2023
daeaca6
Update
TommyTran732 Jul 26, 2023
ceea166
Update
TommyTran732 Jul 27, 2023
b17389f
Push
TommyTran732 Jul 28, 2023
52ee35f
Epic
TommyTran732 Jul 28, 2023
3add340
yesss
TommyTran732 Jul 28, 2023
e42b70e
update
TommyTran732 Jul 28, 2023
e849ac3
Update
TommyTran732 Jul 28, 2023
d825db7
update
TommyTran732 Jul 28, 2023
0067f7b
Update
TommyTran732 Jul 28, 2023
4c71bcf
Update
TommyTran732 Jul 28, 2023
7e38964
fix ZFS mounting
TommyTran732 Aug 17, 2023
36c9277
genhostid
TommyTran732 Aug 17, 2023
e2c953f
epic no https
TommyTran732 Aug 17, 2023
a0326d1
Comment out partner repos
TommyTran732 Aug 17, 2023
e3c8047
Reoder
TommyTran732 Aug 17, 2023
94d5ded
epik
TommyTran732 Aug 17, 2023
a2a76fa
very epik
TommyTran732 Aug 17, 2023
87c01eb
config
TommyTran732 Aug 17, 2023
0b9b0d0
passwd
TommyTran732 Aug 18, 2023
7f73f3b
network
TommyTran732 Aug 18, 2023
4f323e1
remove some nonsense
TommyTran732 Aug 22, 2023
777c101
Update Ubuntu List
TommyTran732 Aug 22, 2023
2082a30
Fixed repos
TommyTran732 Aug 22, 2023
99fdad8
Add failmode
TommyTran732 Aug 24, 2023
0df63b4
Pin compat
TommyTran732 Aug 24, 2023
9701174
blah
TommyTran732 Aug 24, 2023
139ee61
Add ed25519
TommyTran732 Sep 5, 2023
47b3c5c
Add notes
TommyTran732 Sep 5, 2023
91ea900
consistency
TommyTran732 Sep 5, 2023
6dcbc77
Update
TommyTran732 Sep 20, 2023
aca3218
Typo fix
TommyTran732 Sep 20, 2023
c4376d4
purge grub
TommyTran732 Sep 26, 2023
9de2dbf
Add hardened boot param
TommyTran732 Sep 27, 2023
d68d4f2
Update Root ZFS Encryption, Mirroring, and Remote Unlocking with Ubun…
TommyTran732 Oct 22, 2023
143c26e
Fix IOMMU
TommyTran732 Dec 7, 2023
f16c582
Disable 32 bit emulation
TommyTran732 Jan 11, 2024
69e7dae
Update kernel args
TommyTran732 Feb 10, 2024
5e855bb
Remove extra_latent_entropy
TommyTran732 Feb 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,385 @@
---
title: "Root ZFS Encryption, Mirroring, and Remote Unlocking on Ubuntu"
tags: ['Operating Systems', 'Linux', 'Security']
date: 2023-07-26
author: Tommy
---

While Unbutu supports ZFS on root filesystems with an easy snapshot and rollback mechanism called ZSYS, ZSYS is [soon going to be deprecated](https://bugs.launchpad.net/ubuntu/+source/ubiquity/+bug/1966773) and the installer does not offer an easy way to setup mirroring. In this guide, I will walk you through how to set up Ubuntu with root on ZFS, mirroring with both the root and EFI partitions, and remote unlocking + boot into a snapshot with ZFSBootMenu.

![ZFSBootMenu](/images/zfsbootmenu.png)

## Enter the Shell

Enter the shell on your Ubuntu Installer:



## Partitioning the Disk

Esentially, we need a 512MB ESP partition for ZFSBootMenu and a `/` partition for the rest of the system. If you are using a single disk, just make those 2 partitions on your disk. If you are planning to do mirroring, set up both on of these partitions on each disk.

There are a variety of tools you can use, but an easy to use one would be `cfdisk`.

```bash
cfdisk /dev/nvme0n1
cfdisk /dev/nvme0n2
```

![cfdisk](/images/cfdisk.png)

## Mirroring the ESP partition

_Skip this if you are not doing mirroring_

While the EFI specs do not support `mdadm`, we can setup mdadm with metadata v1.0, which will be put at the end of the parition and allows it to boot.

```bash
mdadm --create /dev/md0 --level 1 --raid-disks --metadata 1.0 /dev/nvme0n1p1 /dev/nvme0n1p2
mkfs.fat -F 32 /dev/md0
```

## Setup the ZFS partition

This part is mostly based on the [official ZFSBootMenu guide](https://docs.zfsbootmenu.org/en/v2.2.x/guides/ubuntu/uefi.html) with some changes to work around some not-so-great instructions there.

### Creating the zpool

#### Getting the Disk ID.

First, we must get the disk IDs from `/dev/disk/by-id`. The official guide uses the dynamically assigned drive identifier (`/dev/sda`, `/dev/nvme0n1`, etc), which is not what we want to do with zpools, since it will cause problems later on.

![/dev/disk/by-id](/images/disk-by-id.png)

#### Installing ZFS-Utils

```bash
sudo apt install zfsutils-linux -y
```

#### Create the encryption key

```bash
echo 'SomeKeyphrase' > /etc/zfs/zroot.key
chmod 000 /etc/zfs/zroot.key
```

#### For Non-Mirrored Setups

```bash
sudo zpool create -o ashift=12 -O compression=zstd -O acltype=posixacl -O xattr=sa -O atime=off -O encryption=on -O keylocation=file:///etc/zfs/zroot.key -O keyformat=passphrase -o autotrim=on -o failmode=panic compatibility=openzfs-2.1-linux -m none zroot /dev/disk/by-id/nvme-SAMSUNG_MZQL21T9HCJR-00A07_XXXXXXX-part2
```

#### For Mirrored Setups

```bash
zpool create -o ashift=12 -O compression=zstd -O acltype=posixacl -O xattr=sa -O atime=off -O encryption=on -O keylocation=file:///etc/zfs/zroot.key -O keyformat=passphrase -o autotrim=on -o failmode=panic compatibility=openzfs-2.1-linux -m none zroot mirror /dev/disk/by-id/nvme-SAMSUNG_MZQL21T9HCJR-00A07_XXXXXXX-part2 /dev/disk/by-id/nvme-SAMSUNG_MZQL21T9HCJR-00A07_YYYYYYY-part2
```

#### Notes

We use slightly different options than the official guide. Most notably, `atime` is disabled as it has detrimental effect on performance and unnecessarily increases write operations. `compression` is changed from `lz4` to `zstd` as it has much better compression ratio than `lz4` while still maintaining good performance. We did not specify the encryption type here as `aes-256-gcm` is already the default with openZFS >= 0.8.4. failmode=panic makes sure that the kernel panics in case there is something wrong with the drive instead of taking risks with abnormal behavior. We specify compatibility=openzfs-2.1-linux to make sure that updates will not make the system unbootable in the future.

### Creating the filesystems

```bash
zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/ubuntu
zfs create -o mountpoint=/home zroot/home
zfs create -o mountpoint=/var/log zroot/ROOT/ubuntu/log
zfs create -o mountpoint=/var/spool zroot/ROOT/ubuntu/spool
zfs create -o mountpoint=/var/cache zroot/ROOT/ubuntu/cache

zpool set bootfs=zroot/ROOT/ubuntu zroot
```

Here, we deviate from the official guide by splitting out `/var/log`, `/var/spool`, `/var/cache` out into their own datasets. These are directories which are parts of Ubuntu that we do not want to be rolled back along with the system in case we need to boot into a prior snapshot.

### Mounting the filesystem

```bash
zpool export zroot
zpool import -N -R /mnt zroot
zfs load-key -L prompt zroot
zfs mount zroot/ROOT/ubuntu
zfs mount zroot/ROOT/ubuntu/log
zfs mount zroot/ROOT/ubuntu/cache
zfs mount zroot/ROOT/ubuntu/spool
zfs mount zroot/home
```

### Update device symlink

```bash
udevadm trigger
```

## Install Ubuntu

We will deviate from the ZFSBootMenu's documentation here, as it only installs a minimal system with SysVinit. Instead, we can install ubuntu-server-minimal.

### Bootstrapping

```bash
zgenhostid -f 0x00bab10c
apt install -y debootstrap
debootstrap jammy /mnt
```

### Copy files into the new install

```bash
cp /etc/hostid /mnt/etc/hostid
cp /etc/resolv.conf /mnt/etc/
mkdir /mnt/etc/zfs
cp /etc/zfs/zroot.key /mnt/etc/zfs
```

### Chroot into the new OS

```bash
mount -t proc proc /mnt/proc
mount -t sysfs sys /mnt/sys
mount -B /dev /mnt/dev
mount -t devpts pts /mnt/dev/pts
chroot /mnt /bin/bash
```

### Setup the repositories

Use the source list from the Ubuntu live ISO:

```bash
cat <<EOF > /etc/apt/sources.list
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://archive.ubuntu.com/ubuntu/ jammy main restricted
# deb-src http://archive.ubuntu.com/ubuntu/ jammy main restricted

## Major bug fix updates produced after the final release of the
## distribution.
deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted
# deb-src http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://archive.ubuntu.com/ubuntu/ jammy universe
# deb-src http://archive.ubuntu.com/ubuntu/ jammy universe
deb http://archive.ubuntu.com/ubuntu/ jammy-updates universe
# deb-src http://archive.ubuntu.com/ubuntu/ jammy-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://archive.ubuntu.com/ubuntu/ jammy multiverse
# deb-src http://archive.ubuntu.com/ubuntu/ jammy multiverse
deb http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse
# deb-src http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse
# deb-src http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse

deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted
# deb-src http://security.ubuntu.com/ubuntu/ jammy-security main restricted
deb http://security.ubuntu.com/ubuntu/ jammy-security universe
# deb-src http://security.ubuntu.com/ubuntu/ jammy-security universe
deb http://security.ubuntu.com/ubuntu/ jammy-security multiverse
# deb-src http://security.ubuntu.com/ubuntu/ jammy-security multiverse
EOF
```

### Install the necessary packages

```bash
apt update
apt install --no-install-recommends linux-generic ubuntu-server-minimal
```

### Configure packages to customize local and console properties

```bash
dpkg-reconfigure locales tzdata keyboard-configuration console-setup
```

## ZFS Configuration

### Install required packages

```bash
apt install dosfstools zfs-initramfs zfsutils-linux -y
```

### Enable systemd ZFS services

```bash
systemctl enable zfs.target
systemctl enable zfs-import-cache
systemctl enable zfs-mount
systemctl enable zfs-import.target
```

### Enable systemd-networkd
```bash
systemctl enable systemd-networkd
```

### Configure `initramfs-tools`

```bash
echo "UMASK=0077" > /etc/initramfs-tools/conf.d/umask.conf
```

### Rebuild the initramfs

```bash
update-initramfs -c -k all
```

## Install and configure ZFSBootMenu

### Setup the EFI partition

If you are doing mirroring:

```bash

cat << EOF >> /etc/fstab
$( blkid | grep /dev/md0 | cut -d ' ' -f 2 ) /boot/efi vfat defaults 0 0
EOF

mkdir -p /boot/efi
mount /boot/efi
```

If you are not, just replace `md0` in the commands above with your efi partition.

### Set ZFSBootMenu properties

Next, we will set the kernel boot parameters and the encryption key source for ZFSBootMenu. Here, we will deviate from the official guide and use a hardened boot parameter for better security:

```bash
zfs set org.zfsbootmenu:commandline="quiet loglevel=4 mitigations=auto,nosmt spectre_v2=on spec_store_bypass_disable=on tsx=off kvm.nx_huge_pages=force nosmt=force l1d_flush=on spec_rstack_overflow=safe-ret random.trust_bootloader=off random.trust_cpu=off intel_iommu=on amd_iommu=force_isolation efi=disable_early_pci_dma iommu=force iommu.passthrough=0 iommu.strict=1 slab_nomerge init_on_alloc=1 init_on_free=1 pti=on vsyscall=none ia32_emulation=0 page_alloc.shuffle=1 randomize_kstack_offset=on debugfs=off" zroot/ROOT
zfs set org.zfsbootmenu:keysource="zroot/ROOT/ubuntu" zroot
```

### Install ZFSBootMenu

#### To use it without remote unlocking, just follow the official guide:

```
apt install curl -y
mkdir -p /boot/efi/EFI/ZBM
curl -o /boot/efi/EFI/ZBM/VMLINUZ.EFI -L https://get.zfsbootmenu.org/efi
cp /boot/efi/EFI/ZBM/VMLINUZ.EFI /boot/efi/EFI/ZBM/VMLINUZ-BACKUP.EFI
```

#### To use it with remote unlocking, you have to compile the package:

```bash
git clone https://github.com/zbm-dev/zfsbootmenu
cd zfsbootmenu
make
make install

echo 'Global:
ManageImages: true
BootMountPoint: /boot/efi
DracutConfDir: /etc/zfsbootmenu/dracut.conf.d
PreHooksDir: /etc/zfsbootmenu/generate-zbm.pre.d
PostHooksDir: /etc/zfsbootmenu/generate-zbm.post.d
InitCPIOConfig: /etc/zfsbootmenu/mkinitcpio.conf
Components:
ImageDir: /boot/efi/EFI/zbm
Versions: 3
Enabled: false
syslinux:
Config: /boot/syslinux/syslinux.cfg
Enabled: false
EFI:
ImageDir: /boot/efi/EFI/zbm
Versions: false
Enabled: true
Kernel:
CommandLine: ro quiet loglevel=0 quiet loglevel=4 mitigations=auto,nosmt spectre_v2=on spec_store_bypass_disable=on tsx=off kvm.nx_huge_pages=force nosmt=force l1d_flush=on spec_rstack_overflow=safe-ret random.trust_bootloader=off random.trust_cpu=off intel_iommu=on amd_iommu=force_isolation efi=disable_early_pci_dma iommu=force iommu.passthrough=0 iommu.strict=1 slab_nomerge init_on_alloc=1 init_on_free=1 pti=on vsyscall=none ia32_emulation=0 page_alloc.shuffle=1 randomize_kstack_offset=on debugfs=off' | tee /etc/zfsbootmenu/config.yaml

git clone https://github.com/dracut-crypt-ssh/dracut-crypt-ssh
apt install -y libblkid-dev
cd dracut-crypt-ssh
./configure
make
make install
echo 'omit_dracutmodules+=" crypt-ssh "' >> /etc/dracut-config-location-idk
mkdir -p /etc/dropbear
ssh-keygen -t rsa -m PEM -f /etc/dropbear/ssh_host_rsa_key
ssh-keygen -t ecdsa -m PEM -f /etc/dropbear/ssh_host_ecdsa_key
ssh-keygen -t ed25519 -m PEM -f /etc/dropbear/ssh_host_ed25519_key
mkdir -p /etc/cmdline.d
echo "ip=dhcp rd.neednet=1" > /etc/cmdline.d/dracut-network.conf

cat <<EOF > /etc/zfsbootmenu/dracut.conf.d/dropbear.conf
# Enable dropbear ssh server and pull in network configuration args
add_dracutmodules+=" crypt-ssh "
install_optional_items+=" /etc/cmdline.d/dracut-network.conf "
# Copy system keys for consistent access
dropbear_rsa_key=/etc/dropbear/ssh_host_rsa_key
dropbear_ecdsa_key=/etc/dropbear/ssh_host_ecdsa_key
dropbear_ed25519_key=/etc/dropbear/ssh_host_ed25519_key
# User zbmuser is the authorized unlocker here
dropbear_acl=/home/zbmuser/.ssh/authorized_keys
EOF

generate-zbm
```

### Configure EFI boot entries

```bash
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
apt install efibootmgr -y

efibootmgr -c -d "/dev/nvme0n1" -p 1 \
-L "ZFSBootMenu" \
-l \\EFI\\ZBM\\VMLINUZ.EFI

efibootmgr -c -d /dev/nvme0n1 -p 1 \
-L "ZFSBootMenu (Backup)" \
-l \\EFI\\ZBM\\VMLINUZ-BACKUP.EFI

### Skip this section if you are not doing mirroring

efibootmgr -c -d "/dev/nvme0n2" -p 1 \
-L "ZFSBootMenu 2" \
-l \\EFI\\ZBM\\VMLINUZ.EFI

efibootmgr -c -d /dev/nvme0n2 -p 1 \
-L "ZFSBootMenu 2 (Backup)" \
-l \\EFI\\ZBM\\VMLINUZ-BACKUP.EFI

```

### Set the root password

Set the root password:

```
passwd
```

### Remove grub
apt purge grub* -y

### Exit the environment
```
exit
umount -n -R /mnt
zpool export zroot
reboot
```
Binary file added static/images/cfdisk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/disk-by-id.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/zfsbootmenu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.