User:ZachHilman/Installation - Btrfs + LUKS2 + Secure Boot

From ArchWiki

This article is not officially supported.

The Arch Linux community does not offer support for the information contained in this page; for installation procedures, the Installation guide is the only officially supported document. The content below is mainly maintained by User:ZachHilman, who last reviewed it on 27 October 2022, and it may be out of date or inaccurate.

Notes

Secure Arch Linux setup for a new computer combining Btrfs for the root filesystem, LUKS2 (as opposed to LUKS1) for encryption (this is to allow enrolling a TPM2 into a keyslot), Secure Boot (using sbctl), along with plymouth-gitAUR for a nice boot animation, (optional) TPM2 key enrollment with a PIN instead of entering a password, an encrypted swap partition as opposed to a swapfile, and boot from a Unified kernel image as opposed to GRUB or another traditional bootloader.

I haven't fully evaluated this setup yet, but have successfully installed it twice (in a VM and on hardware). I created this guide due to the lack of single guide combining all of the things I wanted. Any comments appreciated! I try to explain decisions and commands in the guide, but make sure you understand what you run and why. I take no responsibility for insecure or damaged systems.

This guide is inspired by and/or uses steps from:

Identify Drive and Secure Erase

Start

Follow the standard installation guide up to the point where partitioning begins. You will need an internet connection and may want to set up SSH into the install disk so you can use copy/paste and other niceties from a 2nd computer, but it is not required.

(Optional) Secure Erase Disk

Identify the drive you want to install on:

fdisk -l

Dual-booting or multiple OS on a single drive is out of scope of this guide. We are going to completely erase this disk, so make sure there isn't anything important on it.

For the rest of this section, '*DRIVE*' refers to your selected disk from the last step (i.e. '/dev/sda' or '/dev/nvme0n1'

Open a plain encrypted container (with random key) over the entire target drive:

cryptsetup open --type plain *DRIVE* container --key-file /dev/urandom

Make sure the container mounted properly, you should see a disk for '/dev/mapper/container'

fdisk -l

Zero Out the encrypted container. Because of the encryption layer, this will be pseudorandom bits on the actual disk, and because of the random key it will not be possible to determine the pattern here.

dd if=/dev/zero of=/dev/mapper/container status=progress bs=1M

Close the encrypted container

cryptsetup close container

Partition Drive, Encryption, and Filesystems

Partitioning

Optional, but just to ensure no remnants of the secure erase mess anything up, zap the drive

sgdisk --zap-all *DRIVE*

Now do the actual partitioning. You can adjust the sizes of the EFI partition (though at least 300 MB is recommended) and the swap partition (if you have a lot of storage, RAM size + 2GB is good). We are naming drives here so we can use the names instead of potentially volatile names like '/dev/sda'.

sgdisk --clear --new=1:0:+512MiB --typecode=1:ef00 --change-name=1:EFI --new=2:0:+16GiB --typecode=2:8200 --change-name=2:cryptswap --new=3:0:0 --typecode=3:8300 --change-name=3:cryptsystem *DRIVE*

Verify that the partitions are set up properly

fdisk -l


Encrypted Containers

Create the encrypted system partition. Note that we explicitly specify LUKS2 as well as our encryption parameters.

cryptsetup luksFormat --type luks2 --align-payload=8192 -s 256 -c aes-xts-plain64 /dev/disk/by-partlabel/cryptsystem

Open the new encrypted system partition.

cryptsetup open /dev/disk/by-partlabel/cryptsystem system

Swap

Open an encrypted swap container, using a random key.

cryptsetup open --type plain --key-file /dev/urandom /dev/disk/by-partlabel/cryptswap swap

Make swap partition

mkswap -L swap /dev/mapper/swap

Mount swap partition

swapon -L swap

Btrfs

Create the filesystem

mkfs.btrfs --label system /dev/mapper/system

Mount at root

mount -t btrfs LABEL=system /mnt

Create the root subvolume (this will be '/' on the final system)

btrfs subvolume create /mnt/@root

Create the home directory subvolume (this will hold all user data)

btrfs subvolume create /mnt/@home

Create a subvolume for snapshot storage

btrfs subvolume create /mnt/@snapshots

Unmount root so we can change mount options

umount -R /mnt

Remount the root subvolume with options. The compression here is optional, zstd offers the best storage but you may prefer a different algorithm for speed, or omit entirely. Only use ssd if you are on an SSD. You can also enable atime if desired, but it comes with overhead.

mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@root LABEL=system /mnt

Mount the home subvolume (same deal with options as previous step)

mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@home LABEL=system /mnt/home

Mount the snapshots volume to '/.snapshots' (same deal with options as previous step)

mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@snapshots LABEL=system /mnt/.snapshots

EFI System Partition

Format the partition as FAT-32, with label 'EFI'

mkfs.fat -F32 -n EFI /dev/disk/by-partlabel/EFI

Make the mount directory

mkdir /mnt/efi

Mount the ESP

mount LABEL=EFI /mnt/efi

Install Base System

Bootstrap the base system. You can substitute a different kernel here if desired.

pacstrap /mnt base linux linux-firmware

Generate the filesystem table. Unlike the default installation guide, we choose to use labels instead of UUIDs for mounts.

genfstab -L -p /mnt >> /mnt/etc/fstab

We need to edit the fstab to ensure the swap gets mounted correctly. Open the file '/mnt/etc/fstab' and replace 'LABEL=swap' with '/dev/mapper/swap'.

With that change, the kernel will expect an opened encrypted container called swap, so add the following to the file '/mnt/etc/crypttab' to have it opened on boot.

swap /dev/disk/by-partlabel/cryptswap /dev/urandom swap,offset=2048,cipher=aes-xts-plain64,size=256

Note that this will generate a random key every boot, so swap will not be persistent. This has implications on hibernation, so be aware.

Configure System

Basic Configuration

Change root into the new system

arch-chroot /mnt

Set Timezone (you can 'ls /usr/share/zoneinfo' to see options)

ln -sf /usr/share/zoneinfo/*FILL IN*/*FILL IN* /etc/localtime

Set hardware clock offset

hwclock --systohc

Edit the file '/etc/locale.gen' with the locales you want available

Create the locales

locale-gen

Edit '/etc/locale.conf', add the line below with your chosen locale

LANG=*FILL IN*

Set your hostname by editing '/etc/hostname'

Install More Packages

pacman -Syu networkmanager base-devel btrfs-progs gptfdisk nano zsh sudo ttf-dejavu sbctl *intel or amd depending*-ucode polkit

Make sure to select the right microcode package for your architecture

Unified Kernel Image Setup

Edit the HOOKS for mkinitcpio. Replace the HOOKS= line with

HOOKS=(base systemd sd-plymouth modconf keyboard block filesystems btrfs sd-encrypt fsck)

We are switching from busybox-based init to systemd, as it is required in order for plymouth to work with the way we are doing encryption. We also add the btrfs hook, and the encryption hook so our system will get loaded.

Set the kernel parameters by copying the following into '/etc/kernel/cmdline'

fbcon=nodefer rw rd.luks.allow-discards quiet bgrt_disable root=LABEL=system rootflags=subvol=@root,rw splash vt.global_cursor_default=0

We set the options to load the encrypted root, hide extra logging, and load plymouth for the splash screen.

Add the following line into the (new) file '/etc/crypttab.initramfs'. This is like the crypttab, but gets loaded early in boot, so we can use it to load our encrypted system.

system /dev/disk/by-partlabel/cryptsystem none timeout=180,tpm2-device=auto

Notice the 'tpm2-device=auto'. If you don't have a TPM2 or don't want it used to unlock your drive, remove that part and the trailing comma.

Create secure boot keys

sbctl create-keys

Generate the signed Unified Kernel Image bundle

sbctl bundle -s /efi/main.efi

If this doesn't work because of a 'missing EFI system partition', that's likely because of the chroot operation. In that case, prefix the command with 'ESP_PATH=/efi' and run again. As long as there is a file called main.efi in the directory `/efi` it's good for now.

Add UEFI boot entry for the unified kernel image

efibootmgr --create --disk *DRIVE* --part *PARTITION NUMBER* --label "Linux" --loader 'main.efi' --unicode

(Tip: Use 'fdisk -l' to verify drive/partition number)

Users

Set root password

passwd

Create an admin user account. You probably want this anyway, and we need one to build an AUR package (makepkg doesn't like root)

useradd -m -G wheel,storage,power -g users -s/usr/bin/zsh *USERNAME*

Set the new user password

passwd *USERNAME*

Enable sudo access for the wheel group with password. Look for and uncomment the desired like in '/etc/sudoers'

Start shell as the new user

sudo -u *USERNAME* -i

Create a build directory

mkdir Build && cd Build

Clone auraAUR, and AUR helper. Not strictly required, but it's convenient for updating AUR packages in the future. You can alternatively just install plymouth-gitAUR directly.

git clone https://aur.archlinux.org/aura.git

Build aura

cd aura && makepkg -is

Remove the temp directory. Aura will update itself when running 'aura -Au'

cd .. && rm -rf aura

Exit the sudo impersonation

exit

Install plymouth-gitAUR, a splash screen program

aura -Ax plymouth-git

Set the default theme and rebuild the initramfs

plymouth-set-default-theme -R spinner

Regenerate the unified kernel image and sign it

sbctl generate-bundles -s

TPM2 Enrollment

This stop is OPTIONAL. Doing do allows the TPM2 chip of your device to unlock the root partition. Here, this is configured with a PIN (letters/numbers validated by TPM) and set to reject changes to the system configuration. Be sure you understand the security implications of this, and possibly set a dictionary lockout (i.e. too many tries must wait a day) on the PIN

List TPMs

systemd-cryptenroll --tpm2-device=list

There should only be one, otherwise you need to figure out which is the main one and/or pick

systemd-cryptentoll --tpm2-device=*DEVICE FROM LAST STEP* --tpm2-pcrs=0+7 --tpm2-with-pin=yes /dev/disk/by-partlabel/cryptsystem

Finalize

Exit chroot

exit

Reboot into system

reboot

Post-Boot Setup

Reboot the system into UEFI setup. Enable 'Setup Mode' in secure boot settings. MAKE SURE you understand the implications of this, and check to make sure it is safe for your device. Some laptops have been bricked erasing the default keys.

Once booted, login and enroll the secure boot keys. THIS CAN BRICK YOUR DEVICE. On some systems, OpROMs (Option ROMs, essentially UEFI-level device drivers) may be present and required, which have to be signed with secure boot to work. If you do this improperly, the device WILL BE BRICKED. For more information, see sbctl's man pages. ONLY RUN THE FOLLOWING IF YOU KNOW WHAT YOU ARE DOING

sbctl enroll-keys

Enable NTP Time

timedatectl set-ntp true

Closing

If you have any comments, please don't hesitate. Hope this worked well for you and you can use a modern encrypted install.