-- Leo's gemini proxy

-- Connecting to ew.srht.site:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

2022-02-26

alpineLinux: Notebook Installation on encrypted Partitions

tags: software



I'm toying with alpine linux since a while. I am truely impressed by it's slim footprint on the disk. So I have tried it on a Dell Notebook as a "sys" install (everything on disk). Needless to say, it worked like a charm. But how about adding uefi/grub boot and disk encryption? While reading up on available documentation, I came across a detailed post at wejn.org. The author (Michal Jirků?) makes two points:

He wanted to have reasonable defence against the "evil maid attack"

He wanted the whole thing to be reproducible, so he provided a big fat shell script on top


Now that shell script is full of wonders: using nvme disks; using zfs; using software RAID (mdadm) for the non-zfs parts; and on, all the way to using secure boot with his own keys ... what a ride.

https://wejn.org/2021/01/alpinelinux-secure-boot-with-full-encryption/


This bit really triggered my interest:

Use secureboot with your own key to protect grubx64.efi from tampering.

Enable this grubx64.efi to deal with a ext2 filesystem on a luks1 encrypted partition. This way the rest of grub, ie. the modules and most notably its configuration file, reside on encrypted disk space.

After that the boot proceeds normally, the kernel does not even notice, that a secureboot is in progress, if I understand correctly. No worries about kernel updates and messing up signatures.

While we are at it, we place the mantra to open up the remaining encrypted partitions in the same area, so just typing the mantra to open the first partition is sufficient to start the whole system.


There were quite a number of puzzle pieces, which I had been searching before, everything in one place. Fabulous!


So I set out to install alpine linux on a Dell Latitude E6230 with a similar structure:

secureboot, grubx64.efi resides on partition 1 (EFI system partition)

grubx64.efi knows how to decrypt partiton 2 to find its modules and configuration; it will ask for the mantra; that partition also has the kernel and initial ramdisk, which in turn includes the key to open partition 3

partition 3 holds logical volumes on a luks crypto partition. This is where the rest of the system lives: root filesystem, swap and a volume for /home.


The commands to achieve this are listed below. It's not strictly a shell script. Be sure to adapt sizes and key material to your liking. I did repeat this installation on another notebook. Everything worked except for the secureboot step. So I tried another notebook (Dell Latitude E7470) and it worked on the first attempt. So either I did some mistake or omission, or that particular UEFI did not successfully replace the keys.


If you try this, don't follow it blindly! I don't want to hear that you bricked your system. Nonetheless, have the appropriate amount of fun!

Thanks to Michal and others for all the documentation!


Cheers,

~ew


https://alpinelinux.org/

Home


# --- the gory details -----------------------------------------------
# boot an alpinelinux installation stick, possibly with uefi enabled
# once at the login prompt, login as root

# --- install a few more tools
apk add e2fsprogs lsblk parted cryptsetup lvm2 iproute2 bash

# --- delete old boot block and partition table
dd if=/dev/zero of=/dev/sda bs=1M count=20

# --- create new partitions; there might be better ways
parted /dev/sda \
       mklabel gpt \
       mkpart ESP fat32 2048s 256M \
       set 1 esp on set 1 boot on \
       mkpart BOOT ext2 256M 512M \
       mkpart OS   ext2   1G  64G \
       print
partprobe -s /dev/sda

# --- Partition 1: Efi System Partition ------------------------------
#     format
mkfs.vfat -F 32 /dev/sda1                                   # /boot/efi

# --- Partition 2: ext2 for /boot ------------------------------------
#     create a key file. This mantra is intented to be used interactively,
#     hence "echo -n", because in keyfiles, \n will NOT end the input, but
#     EOF will.
echo -n "mai-sikkritt-mantra" > ./p2.mantra
chmod 0600 ./p2.mantra
#     create a crypto_luks1 container on partition 2 (boot)
#     use luks1 format!
cryptsetup luksFormat --type luks1 -d ./p2.mantra /dev/sda2
#     open and format
cryptsetup open -d ./p2.mantra /dev/sda2 sda2_crypt
mkfs.ext2 /dev/mapper/sda2_crypt

# --- Partition 3: crypto_luks1, hosting lvm2 ------------------------
#     create a keyfile. This mantra is not intented to be used interactively.
touch ./crypto_keyfile.bin
chmod 0600 ./crypto_keyfile.bin
dd bs=512 count=4 if=/dev/urandom of=./crypto_keyfile.bin
#    format and open crypto_luks1 container
cryptsetup luksFormat --type luks1 -d ./crypto_keyfile.bin /dev/sda3
cryptsetup open -d ./crypto_keyfile.bin /dev/sda3 sda3_crypt
#    use as physical volume in volume group 0
pvcreate /dev/mapper/sda3_crypt
vgcreate vg0 /dev/mapper/sda3_crypt
#    create 3 logical volumes and format them
lvcreate -a y -l 2048 -n lvroot vg0
lvcreate -a y -l 2048 -n lvswap vg0
lvcreate -a y -l 2048 -n lvhome vg0
mkfs.ext4 /dev/mapper/vg0-lvroot
mkswap    /dev/mapper/vg0-lvswap
swapon    /dev/mapper/vg0-lvswap
mkfs.ext4 /dev/mapper/vg0-lvhome

# --- mount target tree on /mnt --------------------------------------
mount -t ext4 /dev/mapper/vg0-lvroot   /mnt
mkdir /mnt/boot
mount -t ext2 /dev/mapper/sda2_crypt   /mnt/boot
mkdir /mnt/boot/efi
mount /dev/sda1                        /mnt/boot/efi
mkdir /mnt/home
mount -t ext4 /dev/mapper/vg0-lvhome   /mnt/home
#    copy key files
cp -a ./p2.mantra ./crypto_keyfile.bin /mnt/

# --- install alpinelinux on /mnt ------------------------------------
# this part can be automated by creating and editing an "answer file"
setup-timezone  # UTC
setup-alpine -q # us us-altgr-intl
setup-sshd      # openssh
setup-ntp       # chrony
apk add efibootmgr grub-efi
export BOOTLOADER=grub
export USE_EFI=1
setup-disk -m sys /mnt

# --- now play the chroot trick :-) ----------------------------------
#     a number of things need to be configured in the newly
#     installed system. So we make it functional ...
mount -t proc /proc /mnt/proc
mount --rbind /dev /mnt/dev
mount --make-rslave /mnt/dev
mount --rbind /sys /mnt/sys

#    enter chroot
chroot /mnt
PS1="(chroot) $PS1"
apk add grub grub-efi efibootmgr # probably unneeded
apk del syslinux                 # optional

#    create a configuration to generate a grub.cfg file
blkid /dev/sda3 # get UUID, is used in next step
cat <<EOF >/etc/default/grub
GRUB_DISTRIBUTOR="Alpine"
GRUB_TIMEOUT=5
GRUB_DISABLE_SUBMENU=y
GRUB_DISABLE_RECOVERY=true
GRUB_DISABLE_OS_PROBER=y
GRUB_PRELOAD_MODULES="part_gpt cryptodisk luks ext2"
GRUB_ENABLE_CRYPTODISK=y
GRUB_DISABLE_LINUX_PARTUUID=true
GRUB_DISABLE_LINUX_UUID=true
GRUB_CMDLINE_LINUX_DEFAULT="modules=sd-mod,usb-storage,ext4 quiet rootfstype=ext4 cryptroot=UUID=<UUID-OF-sda3> cryptdm=sda3_crypt cryptkey"
EOF
#    generate grub.cfg
grub-mkconfig -o /boot/grub/grub.cfg
#    install grub -> /boot/efi/EFI/alpine/grubx64.efi
grub-install --target=x86_64-efi --efi-directory=/boot/efi

#    generate initramfs; this stage must decrypt sda3, start the
#    volume group and mount lvroot; therefore a few more features
#    need to be enabled; cryptkey will include file /crypto_keyfile.bin
cat <<EOF >/etc/mkinitfs/mkinitfs.conf
features="ata base ide scsi usb virtio ext2 ext4 lvm cryptsetup cryptkey"
EOF
#    refresh initramfs-lts
mkinitfs -c /etc/mkinitfs/mkinitfs.conf -b / $(ls /lib/modules/)

#    enable cryptsetup to open these partitions in the booted system
cat <<EOF >> /etc/conf.d/dmcrypt
target='sda2_crypt'
source='/dev/sda2'
key='/p2.mantra'

target='sda3_crypt'
source='/dev/sda3'
key='/crypto_keyfile.bin'

# fin
EOF

#     make sda2_crypt available during boot
apk add cryptsetup-openrc
rc-update add dmcrypt boot
rc-update add lvm sysinit # ??? sysvinit or boot?

#     edit /etc/fstab; "lsblk -f" is your friend
cat <<EOF >> /etc/fstab
UUID=<UUID-of-sda2_crypt> /boot ext4 rw,relatime 0 2
UUIE=<UUID-of-lvswap>     swap  swap defaults    0 0
EOF
rc-update add swap boot

# --- secureboot -----------------------------------------------------
#     first a set of properly formatted key,cert files are generated
#     files: {KEK,PK,db}.{auth,cer,crt,esl,key}
apk add efi-mkkeys sbsigntool
mkdir /etc/uefi-keys
efi-mkkeys -s "Your Name" -o /etc/uefi-keys
cp /etc/uefi-keys/*.auth /boot/efi/

#     there is a funny error, which can be worked around
sed -i 's/SecureBoot/SecureB00t/' /boot/efi/EFI/alpine/grubx64.efi
#     now we need to sign grub
sbsign --key /etc/uefi-keys/db.key --cert /etc/uefi-keys/db.crt /boot/efi/EFI/alpine/grubx64.efi
mv /boot/efi/EFI/alpine/grubx64.efi.signed /boot/efi/EFI/alpine/grubx64.efi

exit
#    chroot exited
umount -l /mnt/dev
umount -l /mnt/proc
umount -l /mnt/sys

umount /mnt/boot/efi
umount /mnt/boot
umount /mnt/home
umount /mnt
swapoff /dev/mapper/vg0-lvswap
vgchange -a n
cryptsetup close sda3_crypt
cryptsetup close sda2_crypt

reboot


# remove the usb stick

# enter UEFI
# - enable secure boot
# - enable custom key management
# - replace keys db KEK PK (apparently order is significant) with the
#   correspondig *.auth files
# - create a uefi boot entry, if not there
# - save + exit
#
# Now booting up should
# - show grub asking for the mantra of sda2
# - show the grub.cfg menu
# - boot alpine linux and start the system without any further questions
#
# Time to set a password on UEFI
# Time for post-install activities
#
# Congrats!

-- Response ended

-- Page fetched on Sat Apr 20 04:21:02 2024