Full disk encryption secure boot

From Alpine Linux
Revision as of 11:03, 4 August 2022 by Blt (talk | contribs) (small formating improvment)
This material is work-in-progress ...

Do not follow instructions here until this notice is removed.
(Last edited by Blt on 4 Aug 2022.)

This guide is to explain step by step how to setup Alpine Linux with Full Disk Encryption using LUKS2, /boot & / together on the same partition, encrypted swap for hibernation on a nvme drive, with UEFI & Secure Boot. The goal of this guide is to follow the KISS principle, lvm can be added, another file system can be used, multiple partitions for /home; /var/log etc.. can also be added, if running everything in one partition is not meeting your requirements.

Sequence of Events

  • Installing packages
  • Partitioning the disk
  • Configuring LUKS
  • Mounting points and File System
  • Installing Alpine
  • mkinitfs settings & modules
  • Grub settings
  • Configuring Secure Boot

Installing packages

To facilitate the partitioning we will use gdisk :

# apk add lsblk gptfdisk

For encryption, we will use cryptsetup :

# apk add cryptsetup

For using and managing UEFI, multiple packages are needed :

# apk add efibootmgr e2fsprogs grub grub-efi

Partitioning the disk

Let's assume the disk is /dev/nvme0n1 and no partition is present, we will create three partitions :

  • one for UEFI
  • one for /
  • one for swap (hibernation)
# gdisk /dev/nvme0n1
GPT fdisk (gdisk) version 1.0.9.1

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): d
No partitions

Command (? for help): n
Partition number (1-128, default 1): 
First sector (2048-1000215182, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-1000215182, default = 1000214527) or {+-}size{KMGTP}: 512M
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI system partition'

Command (? for help): n
Partition number (2-128, default 2): 
First sector (1048577-1000215182, default = 1050624) or {+-}size{KMGTP}: 
Last sector (1050624-1000215182, default = 1000214527) or {+-}size{KMGTP}: 16G
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8200
Changed type of partition to 'Linux swap'

Command (? for help): n
Partition number (3-128, default 3): 
First sector (1048577-1000215182, default = 33556480) or {+-}size{KMGTP}: 
Last sector (33556480-1000215182, default = 1000214527) or {+-}size{KMGTP}: 
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8309
Changed type of partition to 'Linux LUKS'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/nvme0n1.
The operation has completed successfully.

Configuring LUKS

# cryptsetup -v -c aes-xts-plain64 -s 512 --hash sha512 --pbkdf pbkdf2 --iter-time 5000 --use-random luksFormat /dev/nvme0n1p2

WARNING!
========
This will overwrite data on /dev/nvme0n1p2 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/nvme0n1p2: 
Verify passphrase: 
Key slot 0 created.
Command successful.

# cryptsetup -v -c aes-xts-plain64 -s 512 --hash sha512 --pbkdf pbkdf2 --iter-time 5000 --use-random luksFormat /dev/nvme0n1p3

WARNING!
========
This will overwrite data on /dev/nvme0n1p3 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/nvme0n1p3: 
Verify passphrase: 
Key slot 0 created.
Command successful.

Mounting points and File System

Open the LUKS partitiond we just created:

# cryptsetup luksOpen /dev/nvme0n1p2 nvme0n1p2-crypt
# cryptsetup luksOpen /dev/nvme0n1p3 nvme0n1p3-crypt

Create vfat file system for UEFI partition:

# mkfs.vfat /dev/nvme0n1p1

Create ext4 file system for swap partition:

# mkfs.ext4 /dev/mapper/nvme0n1p2-crypt

Create ext4 file system for / partition:

# mkfs.ext4 /dev/mapper/nvme0n1p3-crypt

Create mounting points and mount partitions : Mount / partition to /mnt :

# mount -t ext4 /dev/mapper/nvme0n1p3-crypt /mnt

Create /boot/efi:

# mkdir /mnt/boot/efi -p

Mount UEFI partition to /mnt/boot/efi :

# mount -t vfat /dev/nvme0n1p1 /mnt/boot/efi

Activate SWAP:

# mkswap /dev/mapper/nvme0n1p2-crypt
# swapon /dev/mapper/nvme0n1p2-crypt

Check partition scheme:

# lsblk
NAME                MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
nvme0n1             259:0    0 476.9G  0 disk  
├─nvme0n1p1         259:1    0   511M  0 part  /mnt/boot/efi
├─nvme0n1p2         259:2    0  15.5G  0 part  
│ └─nvme0n1p2-crypt 253:0    0  15.5G  0 crypt [SWAP]
└─nvme0n1p3         259:3    0 460.9G  0 part  
  └─nvme0n1p3-crypt 253:1    0 460.9G  0 crypt /mnt

Installing Alpine

# setup-disk -m sys /mnt/

mkinitfs settings & modules

Edit the /mnt/etc/mkinitfs/mkinitfs.conf file and append the cryptsetup module to the features parameter (keymap only needed if QWERTY is not used):

features="...keymap cryptsetup cryptkey"

Regenerate the initram:

# mkinitfs -c /mnt/etc/mkinitfs/mkinitfs.conf -b /mnt/ $(ls /mnt/lib/modules/)

Grub settings

Create a crypto_keyfile.bin to avoid typing the passphrase twice during the boot process (one for Grub partition, one for Alpine partition):

# touch /mnt/crypto_keyfile.bin
# chmod 600 /mnt/crypto_keyfile.bin
# dd bs=512 count=4 if=/dev/urandom of=/mnt/crypto_keyfile.bin
# cryptsetup luksAddKey /dev/nvme0n1p3 /mnt/crypto_keyfile.bin

Then, let's mount and chroot to our fresh installation:

# mount -t proc /proc /mnt/proc
# mount --rbind /dev /mnt/dev
# mount --make-rslave /mnt/dev
# mount --rbind /sys /mnt/sys
# chroot /mnt

Let's show the UUID of our partition scheme:

# lsblk -f

Edit /etc/default/grub and add a new line starting with GRUB_CMDLINE_LINUX parameter, replacing <UUID> with the UUID of the encrypted partition (in this case /dev/nvme0n1p3) and adding a new GRUB_PRELOAD_MODULES line like this:

GRUB_CMDLINE_LINUX="cryptroot=UUID=<UUID> cryptdm=nvme0n1p3-crypt cryptkey"
GRUB_PRELOAD_MODULES="luks cryptodisk part_gpt"

Create a /root/grub-pre.cfg and replace <UUID_WITHOUT_HYPHENS> with your encrypted root partition UUID (here /dev/nvme0n1p3) without hyphens

set crypto_uuid=<UUID_WITHOUT_HYPHENS>
cryptomount -u $crypto_uuid
set root=crypto0
set prefix=($root)/boot/grub
insmod normal
normal

Configuring Secure Boot

# apk add efi-mkkeys efibootmgr
# efi-mkkeys -s "Your Name" -o /etc/uefi-keys
# echo 'disable_trigger=yes' >> /etc/mkinitfs/mkinitfs.conf

Re-install Grub:

# grub-mkimage -p /boot/grub -O x86_64-efi -c /root/grub-pre.cfg -o /tmp/grubx64.efi luks2 part_gpt cryptodisk ext2 gcry_rijndael pbkdf2 gcry_sha512
# install -v /tmp/grubx64.efi /boot/efi/EFI/AlpineLinuxSecureBoot/
# sed -i 's/SecureBoot/SecureB00t/' /boot/efi/EFI/AlpineLinuxSecureBoot/grubx64.efi
# cd /boot/efi/EFI/AlpineLinuxSecureBoot/
# sbsign --key /etc/uefi-keys/db.key --cert /etc/uefi-keys/db.crt --output grubx64.efi.signed grubx64.efi
# grub-mkconfig -o /boot/grub/grub.cfg
# efibootmgr --disk /dev/nvme0n1p1 --part 1 --create --label 'Alpine Linux Secure Boot Signed' --load /EFI/AlpineLinuxSecureBoot/grubx64.efi.signed --verbose

Reboot

Check Secure Boot State:

# apk add mokutil
# mokutil --sb-state
SecureBoot enabled

Congrats!