Compare commits
No commits in common. "b18efc9901c56a7d2adfa6dc326b7dfd91c304ad" and "843d0a373adc8753bedbd079035292435aafc2eb" have entirely different histories.
b18efc9901
...
843d0a373a
3 changed files with 71 additions and 66 deletions
|
@ -1,5 +1,5 @@
|
|||
# An Alpine Linux server installation
|
||||
|
||||
This guide will demonstrate how to install [Alpine Linux](https://www.alpinelinux.org/) for server application. Alpine Linux will run on a raid configured encrypted ZFS filesystem with automatic decryption using TPM. User containers will be configured with `podman` and managed with `runsvdir`.
|
||||
This guide will demonstrate how to install [Alpine Linux](https://www.alpinelinux.org/) for server application. Alpine Linux will run on a raid configured encrypted ZFS filesystem with automatic decryption with TPM. User containers will be configured with podman and managed with runsvdir.
|
||||
|
||||
Alpine Linux makes a good base for a server because of its simplicity, lightweightness and security. Check out the [Alpine Linux wiki](https://wiki.alpinelinux.org/wiki/Main_Page) for additional resources and information.
|
|
@ -2,36 +2,38 @@
|
|||
|
||||
To install the Alpine Linux distribution on the system, the datasets of the system pool and the EFI partitions have to be mounted to the main system.
|
||||
|
||||
First import and decrypt the system pool:
|
||||
First import and decrypt the system pool.
|
||||
|
||||
```
|
||||
# zpool import -N -R /mnt tank
|
||||
# zfs load-key -L file:///tmp/tank.key tank
|
||||
```
|
||||
|
||||
Mount the datasets in the system pool and decrypt the home dataset:
|
||||
Mount the datasets in the system pool and decrypt the home dataset.
|
||||
|
||||
```
|
||||
# mount tank/root/alpine /mnt -t zfs -o noatime
|
||||
# zfs mount tank/root/alpine
|
||||
# zfs mount tank/home
|
||||
# zfs mount tank/var
|
||||
```
|
||||
|
||||
Mount the ESP:
|
||||
Mount the ESP.
|
||||
|
||||
```
|
||||
# mkdir /mnt/esp
|
||||
# mount /dev/md/esp /mnt/esp -t vfat
|
||||
```
|
||||
|
||||
Then install Alpine Linux:
|
||||
Then install Alpine Linux.
|
||||
|
||||
```
|
||||
# export BOOTLOADER=none
|
||||
# setup-disk -m sys /mnt
|
||||
```
|
||||
|
||||
To have a functional chroot into the system, bind the system process directories:
|
||||
> This will also add `grub` as bootloader which will be replaced but for now it will reside on the ESP.
|
||||
|
||||
To have a functional chroot into the system, bind the system process directories.
|
||||
|
||||
```
|
||||
# for dir in dev proc sys run; do
|
||||
|
@ -65,7 +67,7 @@ clock_hctosys="NO"
|
|||
clock_systohc="NO"
|
||||
```
|
||||
|
||||
Configure the ESP raid array to mount:
|
||||
Configure the ESP raid array to mount.
|
||||
|
||||
```
|
||||
# modprobe raid1
|
||||
|
@ -75,50 +77,61 @@ Configure the ESP raid array to mount:
|
|||
# rc-update add mdadm-raid boot
|
||||
```
|
||||
|
||||
Configure ZFS to mount:
|
||||
Configure ZFS to mount.
|
||||
|
||||
```
|
||||
rc-update add zfs-import sysinit
|
||||
rc-update add zfs-mount sysinit
|
||||
rc-update add zfs-load-key sysinit
|
||||
```
|
||||
|
||||
> If a faster boot time is preferred, `zfs-import` and `zfs-load-key` can be omitted in certain cases.
|
||||
|
||||
Edit `/etc/fstab` for correct mounts:
|
||||
|
||||
```
|
||||
/dev/md/esp /esp vfat defaults,nodev,nosuid,noexec 0 2
|
||||
tmpfs /tmp tmpfs rw,nodev,nosuid,noexec,mode=1777 0 0
|
||||
tmpfs /tmp tmpfs rw,size=4G,nr_inodes=5k,nodev,nosuid,noexec,mode=1777 0 0
|
||||
proc /proc proc nodev,nosuid,noexec,hidepid=2 0 0
|
||||
```
|
||||
|
||||
Install the following packages to make `mkinitfs` compatible with secureboot and TPM decryption:
|
||||
By default, Alpine Linux uses `mkinitfs` to create an initial ram filesystem, although it is minimal that also means that it lacks some functionality which is needed for a proper setup. Because of this `mkinitfs` and `grub-efi `will be replaced with `booster` and `secureboot-hook`.
|
||||
|
||||
```
|
||||
# apk add secureboot-hook sbctl tpm2-tools zlevis
|
||||
# apk add booster secureboot-hook sbctl
|
||||
# apk del mkinitfs grub-efi
|
||||
```
|
||||
|
||||
Configure `/etc/mkinitfs/mkinitfs.conf` to disable trigger and to add the `zlevis-hook`:
|
||||
To configure booster edit `/etc/booster.yaml`:
|
||||
|
||||
```
|
||||
features="... zlevis"
|
||||
disable_trigger="yes"
|
||||
enable_zfs: true
|
||||
busybox: false
|
||||
modules: vfat,nls_cp437,nls_iso8859_1
|
||||
```
|
||||
|
||||
The most important step is the creation of a UKI using `secureboot-hook` which also automatically signs them. Configure `/etc/kernel-hooks.d/secureboot.conf` to set kernel cmdline options and secureboot:
|
||||
The most important step is the creation of a UKI using `secureboot-hook` which also automatically signs them. First the hook itself will have to be tweaked to use `booster` instead of `mkinitfs`, edit `/etc/kernel-hooks.d/50-secureboot.hook` and change the line:
|
||||
|
||||
```
|
||||
cmdline="rw root=ZFS=tank/root/alpine rootflags=noatime quiet splash"
|
||||
/sbin/mkinitfs -o "$tmpdir"/initramfs "$NEW_VERSION-$FLAVOR"
|
||||
```
|
||||
|
||||
signing_cert="/var/lib/sbctl/keys/db/db.pem"
|
||||
signing_key="/var/lib/sbctl/keys/db/db.key"
|
||||
to:
|
||||
|
||||
```
|
||||
/usr/bin/booster build "$tmpdir"/initramfs --kernel-version "$NEW_VERSION-$FLAVOR"
|
||||
```
|
||||
|
||||
and configure `/etc/kernel-hooks.d/secureboot.conf` for cmdline and secureboot.
|
||||
|
||||
```
|
||||
cmdline="rw zfs=tank/root/alpine quiet splash"
|
||||
|
||||
signing_cert="/usr/share/secureboot/keys/db/db.pem"
|
||||
signing_key="/usr/share/secureboot/keys/db/db.key"
|
||||
|
||||
output_dir="/esp/efi/linux"
|
||||
output_name="alpine-linux-{flavor}.efi"
|
||||
```
|
||||
|
||||
Use `sbctl` to create secureboot keys and sign them:
|
||||
Use `sbctl` to create secureboot keys and sign them.
|
||||
|
||||
```
|
||||
# sbctl create-keys
|
||||
|
@ -127,7 +140,7 @@ Use `sbctl` to create secureboot keys and sign them:
|
|||
|
||||
> Whilst enrolling the keys it might be necessary to add the `--microsoft` flag if you are unable to use custom keys.
|
||||
|
||||
Set the cache-file of the ZFS pool:
|
||||
Set the cache-file of the ZFS pool.
|
||||
|
||||
```
|
||||
# zpool set cachefile=/etc/zfs/zpool.cache tank
|
||||
|
@ -139,15 +152,9 @@ Now to see if everything went successfully, run:
|
|||
# apk fix kernel-hooks
|
||||
```
|
||||
|
||||
Now to see if everything went successfully, run:
|
||||
|
||||
```
|
||||
# apk fix kernel-hooks
|
||||
```
|
||||
|
||||
and it should give no warnings if done properly.
|
||||
|
||||
To install `gummiboot` as friendly bootloader:
|
||||
As discussed earlier `grub` will be replaced, install `gummiboot` as a bootloader.
|
||||
|
||||
```
|
||||
# apk add gummiboot
|
||||
|
@ -156,7 +163,7 @@ To install `gummiboot` as friendly bootloader:
|
|||
# cp /usr/lib/gummiboot/gummibootx64.efi /esp/efi/boot/bootx64.efi
|
||||
```
|
||||
|
||||
Sign the bootloader with `sbctl`:
|
||||
Sign the bootloader with `sbctl`.
|
||||
|
||||
```
|
||||
# sbctl sign -s /esp/efi/boot/bootx64.efi
|
||||
|
@ -164,7 +171,15 @@ Sign the bootloader with `sbctl`:
|
|||
|
||||
> One may verify the signed files by running `sbctl verify`, in this case `ESP_PATH=/esp` should be defined to work properly.
|
||||
|
||||
`gummiboot` can be configured with the file `/esp/loader/loader.conf` with which the timeout and the default OS can be specified:
|
||||
Remove some remnants of `grub`.
|
||||
|
||||
```
|
||||
# rm -rf /boot/grub
|
||||
# rm -rf /etc/default
|
||||
# cd /boot && unlink boot && cd ..
|
||||
```
|
||||
|
||||
`gummiboot` can be configured with the file `/esp/loader/loader.conf` with which the timeout and the default OS can be specified.
|
||||
|
||||
```
|
||||
default alpine-linux-lts.efi
|
||||
|
@ -172,6 +187,8 @@ timeout 2
|
|||
editor no
|
||||
```
|
||||
|
||||
> Here, there should be lines explaining the setup of automatic decryption with TPM using Clevis. Which is still in development...
|
||||
|
||||
Now exit the chroot and you should be able to reboot into a working Alpine system.
|
||||
|
||||
```
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# Provisioning
|
||||
|
||||
Flash the Alpine Linux extended ISO and make sure the secureboot keys are reset and TPM is enabled in the BIOS of the host.
|
||||
|
||||
After booting the Alpine Linux extended ISO, partition the disks. For this action internet is required since `zfs`, `sgdisk` and various other necessary packages are not included on the extended ISO, therefore they need to be obtained from the alpine package repository.
|
||||
After flashing the Alpine Linux extended ISO, partition the disks. For this action internet is required since `zfs` and `sgdisk` are not included on the extended ISO, therefore it needs to be obtained from the repository.
|
||||
|
||||
To set it up `setup-interfaces` and `setup-apkrepos` will be used.
|
||||
|
||||
|
@ -11,12 +9,10 @@ To set it up `setup-interfaces` and `setup-apkrepos` will be used.
|
|||
# setup-apkrepos -c1
|
||||
```
|
||||
|
||||
> To use Wi-Fi simply run `setup-interfaces -r` and select `wlan0` or similar.
|
||||
|
||||
A few packages will have to be installed first,
|
||||
A few packages will have to be installed first:
|
||||
|
||||
```
|
||||
# apk add zfs lsblk sgdisk wipefs dosfstools acpid mdadm tpm2-tools zlevis
|
||||
# apk add zfs lsblk sgdisk wipefs dosfstools acpid mdadm
|
||||
```
|
||||
|
||||
and load the ZFS kernel module
|
||||
|
@ -25,7 +21,7 @@ and load the ZFS kernel module
|
|||
# modprobe zfs
|
||||
```
|
||||
|
||||
Define the disks you want to use for this install,
|
||||
Define the disks you want to use for this install
|
||||
|
||||
```
|
||||
# export disks="/dev/disk/by-id/<id-disk-1> ... /dev/disk/by-id/<id-disk-n>"
|
||||
|
@ -35,7 +31,7 @@ with `<id-disk-n>` for $n \in \mathbb{N}$ the `id` of the disk.
|
|||
|
||||
> According to [openzfs-FAQ](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/FAQ.html) using `/dev/disk/by-id/` is the best practice for small pools. For larger pools, using serial Attached SCSI (SAS) and the like, see [vdev_id](https://openzfs.github.io/openzfs-docs/man/master/5/vdev_id.conf.5.html) for proper configuration.
|
||||
|
||||
Wipe the existing disk partitions:
|
||||
Wipe the existing disk partitions
|
||||
|
||||
```
|
||||
# for disk in $disks; do
|
||||
|
@ -45,7 +41,7 @@ Wipe the existing disk partitions:
|
|||
> done
|
||||
```
|
||||
|
||||
Create on each disk an `EFI system` partition (ESP) and a `Linux filesystem` partition:
|
||||
Create on each disk an `EFI system` partition (ESP) and a `Linux filesystem` partition
|
||||
|
||||
```
|
||||
# for disk in $disks; do
|
||||
|
@ -54,13 +50,13 @@ Create on each disk an `EFI system` partition (ESP) and a `Linux filesystem` par
|
|||
> done
|
||||
```
|
||||
|
||||
Create device nodes:
|
||||
Create device nodes
|
||||
|
||||
```
|
||||
# mdev -s
|
||||
```
|
||||
|
||||
Define the EFI partitions:
|
||||
Define the EFI partitions
|
||||
|
||||
```
|
||||
# export efiparts=""
|
||||
|
@ -70,7 +66,7 @@ Define the EFI partitions:
|
|||
> done
|
||||
```
|
||||
|
||||
Create a `mdraid` array on the EFI partitions:
|
||||
Create a `mdraid` array on the EFI partitions
|
||||
|
||||
```
|
||||
# modprobe raid1
|
||||
|
@ -78,7 +74,7 @@ Create a `mdraid` array on the EFI partitions:
|
|||
# mdadm --assemble --scan
|
||||
```
|
||||
|
||||
Format the array with a FAT32 filesystem:
|
||||
Format the array with a FAT32 filesystem
|
||||
|
||||
```
|
||||
# mkfs.fat -F 32 /dev/md/esp
|
||||
|
@ -96,15 +92,15 @@ Define the pool partitions
|
|||
> done
|
||||
```
|
||||
|
||||
The ZFS system pool is going to be encrypted. First generate an encryption key and save it temporarily to the file `/tmp/tank.key` with:
|
||||
The ZFS system pool is going to be encrypted. First generate an encryption key and save it temporarily to the file `/tmp/crypt-key.txt` with:
|
||||
|
||||
```
|
||||
# cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1 > /tmp/tank.key && cat /tmp/tank.key
|
||||
```
|
||||
|
||||
> Later on in the guide `zlevis` will be used for automatic decryption, so this key only has to be entered a few times. However, if any changes are made to the bios or secureboot then this key will be needed again, so make sure to save it.
|
||||
> Later on in the guide `clevis` will be used for automatic decryption, so this key only has to be entered a few times. However, if any changes are made to the bios or secureboot then this key will be needed again, so make sure to write it down.
|
||||
|
||||
Create the system pool:
|
||||
Create the system pool
|
||||
|
||||
```
|
||||
# zpool create -f \
|
||||
|
@ -115,33 +111,25 @@ Create the system pool:
|
|||
-O dnodesize=auto \
|
||||
-O encryption=on \
|
||||
-O keyformat=passphrase \
|
||||
-O keylocation=prompt \
|
||||
-O keylocation=file:///tmp/tank.key \
|
||||
-m none \
|
||||
tank raidz1 $poolparts
|
||||
```
|
||||
|
||||
> Additionally, the `spare` option can be used to indicate spare disks. If more redundancy is preferred than `raidz2` and `raidz3` are possible [alternatives](https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html) for `raidz1`. If a single disk is used the `raidz` option can be left aside. For further information see [zpool-create](https://openzfs.github.io/openzfs-docs/man/master/8/zpool-create.8.html).
|
||||
|
||||
Then create the system datasets:
|
||||
Then create the system datasets
|
||||
|
||||
```
|
||||
# zfs create -o mountpoint=none tank/root
|
||||
# zfs create -o mountpoint=legacy -o quota=24g tank/root/alpine
|
||||
# zfs create -o canmount=noauto -o mountpoint=/ -o atime=off -o quota=24g tank/root/alpine
|
||||
# zfs create -o mountpoint=/home -o atime=off -o setuid=off -o devices=off -o quota=<home-quota> tank/home
|
||||
# zfs create -o mountpoint=/var -o atime=off -o exec=off -o setuid=off -o devices=off -o quota=16g tank/var
|
||||
# zfs create -o mountpoint=/var -o exec=off -o setuid=off -o devices=off -o quota=16g tank/var
|
||||
```
|
||||
|
||||
> Setting the `<home-quota>` depends on the total size of the pool, generally try to reserve some empty space in the pool.
|
||||
|
||||
Write the encryption key to TPM and store the jwe in tpm:jwe:
|
||||
|
||||
```
|
||||
# zfs set tpm:jwe=$(zlevis-encrypt '{}' < /tmp/tank.key) tank
|
||||
```
|
||||
|
||||
> To check if it worked, perform `zfs list -Ho tpm:jwe tank | zlevis-decrypt`.
|
||||
|
||||
Finally, export the zpool:
|
||||
Finally, export the zpool
|
||||
|
||||
```
|
||||
# zpool export tank
|
||||
|
|
Loading…
Reference in a new issue