This commit is contained in:
Nils 2024-10-27 12:04:30 +01:00
parent 843d0a373a
commit 440a2b9dce
3 changed files with 103 additions and 79 deletions

View file

@ -1,5 +1,5 @@
# An Alpine Linux desktop installation
This guide will demonstrate how to install [Alpine Linux](https://www.alpinelinux.org/) with encryption, secureboot and a graphical wayland session using wayfire. Alpine Linux makes a perfect base for those who want a minimal, simple and secure Linux installation. This installation will also make use of [Nix](https://nixos.org/) and [Home-manager](https://github.com/nix-community/home-manager) which allows for easy deployment and user independent packages. Check out the [Alpine Linux wiki](https://wiki.alpinelinux.org/wiki/Main_Page) for additional resources and information.
This guide will demonstrate how to install [Alpine Linux](https://www.alpinelinux.org/) with encryption, secureboot and a graphical wayland session using wayfire. Alpine Linux makes a perfect base for those who want a minimal, simple and secure Linux installation. Check out the [Alpine Linux wiki](https://wiki.alpinelinux.org/wiki/Main_Page) for additional resources and information.
> Note that all this documentation is focused on the `x86_64` architecture.

View file

@ -1,26 +1,41 @@
# Installation
To install the Alpine Linux distribution on the system, the alpine root partition and the EFI partition have to be mounted to the main system.
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.
```
# zpool import -N -R /mnt tank
# zfs load-key tank
```
Mount the datasets in the system pool and decrypt the home dataset.
```
# mount tank/root/alpine /mnt -t zfs -o noatime
# zfs mount tank/home
# zfs mount tank/var
```
Mount the ESP.
```
# mount /dev/vg/alpine_root /mnt -t ext4
# mkdir /mnt/esp
# mount /dev/disk/by-label/esp /mnt/esp -t vfat
```
Then install Alpine Linux using `setup disk`
Then install Alpine Linux.
```
# export BOOTLOADER=none
# setup-disk -m sys /mnt
```
> 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
To have a functional chroot into the system, bind the system process directories.
```
# for i in dev proc sys run; do
> mount --rbind --make-rslave /$i /mnt/$i
# for dir in dev proc sys run; do
> mount --rbind --make-rslave /$dir /mnt/$dir
> done
# chroot /mnt
```
@ -33,7 +48,6 @@ The other setup scripts can be used to configure key aspects of the system. Besi
# setup-timezone -i <area>/<subarea>
# setup-ntp openntpd
# rc-update add acpid default
# rc-update add lvm boot
# rc-update add seedrng boot
# rm -rf /var/tmp
# ln -s /tmp /var/tmp
@ -50,49 +64,48 @@ clock_hctosys="NO"
clock_systohc="NO"
```
Edit `/etc/fstab` for correct mounts
Configure the ESP raid array to mount.
```
/dev/disk/by-label/esp /esp vfat defaults,nodev,nosuid,noexec 0 2
/dev/vg/alpine_root / ext4 defaults,noatime 0 1
/dev/vg/home /home ext4 defaults,noatime,nodev,nosuid 0 2
/dev/vg/var /var ext4 defaults,nodev,nosuid,noexec 0 2
/dev/vg/nix /nix ext4 defaults,noatime,nodev,nosuid 0 2
tmpfs /tmp tmpfs rw,size=4G,nr_inodes=5k,nodev,nosuid,noexec,mode=1777 0 0
# modprobe raid1
# echo raid1 >> /etc/modules-load.d/raid1.conf
# mdadm --detail --scan >> /etc/mdadm.conf
# rc-update add mdadm boot
# rc-update add mdadm-raid boot
```
Configure ZFS to mount.
```
rc-update add zfs-import sysinit
rc-update add zfs-mount sysinit
```
Edit `/etc/fstab` for correct mounts:
```
tank/root/alpine / zfs rw,noatime,xattr,posixacl,casesensitive 0 1
/dev/md/esp /esp vfat defaults,nodev,nosuid,noexec 0 2
tmpfs /tmp tmpfs rw,nodev,nosuid,noexec,mode=1777 0 0
proc /proc proc nodev,nosuid,noexec,hidepid=2 0 0
```
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`.
By default, Alpine Linux uses `mkinitfs` to create an initial ram filesystem.
```
# apk add booster secureboot-hook sbctl
# apk del mkinitfs grub-efi
# apk add secureboot-hook sbctl
```
To configure booster edit `/etc/booster.yaml`:
Configure `/etc/mkinitfs/mkinitfs.conf` to disable it's hook:
```
enable_lvm: true
busybox: false
modules: vfat,nls_cp437,nls_iso8859_1
# echo 'disable_trigger=yes' >> /etc/mkinitfs/mkinitfs.conf
```
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:
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` for cmdline and secureboot.
```
/sbin/mkinitfs -o "$tmpdir"/initramfs "$NEW_VERSION-$FLAVOR"
```
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 rd.luks.name=<uuid>=luks rd.lvm.vg=vg root=/dev/vg/alpine_root modules=ext4 quiet splash"
cmdline="rw root=ZFS=tank/root/alpine quiet splash"
signing_cert="/usr/share/secureboot/keys/db/db.pem"
signing_key="/usr/share/secureboot/keys/db/db.key"
@ -101,12 +114,6 @@ output_dir="/esp/efi/linux"
output_name="alpine-linux-{flavor}.efi"
```
Here `<uuid>` has to be replaced with the UUID of the partition which contains the volume group:
```
# blkid /dev/<disk>2 >> /etc/kernel-hooks.d/secureboot.conf
```
Use `sbctl` to create secureboot keys and sign them.
```
@ -116,7 +123,13 @@ 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.
Now to see if everything went succesfully run:
Set the cache-file of the ZFS pool.
```
# zpool set cachefile=/etc/zfs/zpool.cache tank
```
Now to see if everything went successfully, run:
```
# apk fix kernel-hooks
@ -124,7 +137,7 @@ Now to see if everything went succesfully run:
and it should give no warnings if done properly.
As discussed earlier `grub` will be replaced, install `gummiboot` as a bootloader.
To install `gummiboot` as friendly bootloader:
```
# apk add gummiboot
@ -133,28 +146,28 @@ As discussed earlier `grub` will be replaced, install `gummiboot` as a bootloade
# 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
```
and also remove some remnants of `grub`.
```
# rm -rf /boot/grub
# rm -rf /etc/default
# cd /boot && unlink boot && cd ..
```
> 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.
```
default alpine-linux-<flavor>.efi
timeout 2
default alpine-linux-lts.efi
timeout 5
editor no
```
> Here, there should be lines explaining the setup of automatic decryption with TPM using Clevis. Which is still in development...
```
# clevis encrypt tpm2 '{}' << ''
```
Before finishing the installation `networkmanager` will be installed for networking. Also install `networkmanager-wifi` and `wpa_supplicant` for Wi-Fi functionality.
```
@ -163,16 +176,15 @@ Before finishing the installation `networkmanager` will be installed for network
# rc-update add networkmanager default
```
Wi-Fi will not yet work. For Wi-Fi configuration see the [network section](post-install/network).
Wi-Fi will not yet work. For Wi-Fi configuration see the network section.
> If internet does not work after reboot create the config file as described in the [network section](post-install/network) and restart the service.
> If internet does not work after reboot create the config file as described in the network section and restart the service.
Now exit the chroot and you should be able to reboot into a working Alpine system.
```
# exit
# umount -lf /mnt
# zpool export tank
# reboot
```
When booting up your screen might appear blank, this is the encryption prompt. Enter the encryption key and press enter to boot.

View file

@ -9,15 +9,24 @@ To set it up `setup-interfaces` and `setup-apkrepos` will be used.
# setup-apkrepos -c1
```
> To use wifi simply run `setup-interfaces -r` and select `wlan0` or similar.
A few packages will have to be installed first:
```
# apk add e2fsprogs cryptsetup lvm2 lsblk sgdisk wipefs dosfstools acpid
# apk add zfs lsblk sgdisk wipefs dosfstools acpid
```
and load the ZFS kernel module
```
# modprobe zfs
```
Wipe the existing disk partitions
```
# zpool labelclear -f /dev/<disk>
# wipefs -a /dev/<disk>
# sgdisk --zap-all /dev/<disk>
```
@ -41,45 +50,48 @@ Then, format the ESP with a FAT32 filesystem
# mkfs.fat -F 32 -n esp /dev/<disk>1
```
## Volume group creation
## ZFS pool creation
The root partition of the system is going to be encrypted using `cryptsetup`. First generate a key that will be used to encrypt the device and save it temporarily to the file `/tmp/luks.key` with:
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:
```
# cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1 > /tmp/luks.key && cat /tmp/luks.key
# 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 `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 secure-boot then this key will be needed again, so make sure to write it down.
> 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.
Then format the partition using `cryptsetup`:
Create the system pool:
```
# cryptsetup luksFormat /dev/<disk>2 --type luks2 --cipher aes-xts-plain64 --hash sha512 --iter-time 4000 --key-size 512 --pbkdf argon2id
[Enter the generated key]
# cryptsetup open --type luks /dev/<disk2> luks
# zpool create -f \
-o ashift=12 \
-O canmount=off \
-O compression=lz4 \
-O acltype=posix \
-O xattr=sa \
-O dnodesize=auto \
-O atime=off \
-O normalization=formD \
-O encryption=on \
-O keyformat=passphrase \
-O keylocation=prompt \
-m none \
tank /dev/<disk2>
```
Create the LVM volume group
Then create the system datasets:
```
# vgcreate vg /dev/mapper/luks
# zfs create -o mountpoint=none tank/root
# zfs create -o mountpoint=legacy -o quota=24g tank/root/alpine
# zfs create -o mountpoint=/home -o setuid=off -o devices=off -o quota=<home-quota> tank/home
# zfs create -o mountpoint=/var -o exec=off -o setuid=off -o devices=off -o quota=16g tank/var
```
Then create partitions inside the volume group:
> Setting the `<home-quota>` depends on the total size of the pool, generally try to reserve some empty space in the pool.
Finally, export the zpool:
```
# lvcreate --name alpine_root -L 24G vg
# lvcreate --name home -L <home-quota> vg
# lvcreate --name var -L 16G vg
# lvcreate --name nix -L 32G vg
```
> Setting the `<home-quota>` depends on the total size of the volume group, generally try to reserve some empty space in the volume group.
Create the filesystems on the logical partitions:
```
for i in alpine_root home var nix; do
> mkfs.ext4 /dev/vg/$i
> done
# zpool export tank
```