aboutsummaryrefslogtreecommitdiff
path: root/posts/void-linux-with-encrypted-root-on-zfs.md
blob: 3179b4c6639a8a1d2a064aa04763ad358199bab7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# Installing Void Linux with encrypted Root on ZFS
#### 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<br>
<https://forum.level1techs.com/t/chains-computar-projects/190001>

> Daniel Wayne Armstrong Blog<br>
<https://www.dwarmstrong.org/encrypt-swap/>

# To start
Download the latest hrmpf image from:<br>
<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`.
<br>
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 with `mountpoint=/` (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, setting `canmount=noauto` on `zroot/ROOT` is not sufficient, as any subsequent boot environments you create will default to `canmount=on`. It is necessary to explicitly set the `canmount=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
```