User:Thawn

From ArchWiki

Here is a draft of a rewrite of Dm-crypt/Encrypting_an_entire_system#Btrfs_subvolumes_with_swap. The main motivation is that the current guide is very difficult to follow because it is lacking specific commands. Also the references it gives are quite vague and make it difficult to figure out which sections of the referenced articles should be followed.

I am looking forward to your edits, comments and discussion :)


Btrfs on LUKS

The following example creates a full system encryption with LUKS1 using Btrfs as filesystem and btrfs subvolumes to simulate partitions. That way you combine the security of a fully encrypted system with the advantages of Btrfs.

Getting started

Follow the Installation_guide until the step Installation_guide#Partition_the_disks

Note: This means you should now be booted into the live system

Prior to creating any partitions, you should inform yourself about the importance and methods to securely erase the disk, described in dm-crypt/Drive preparation.

In this guide we assume you are using UEFI. Therefore, an EFI system partition (ESP) is required. The ESP itself cannot be encrypted. the ESP is /dev/sda1 and is mounted at /efi. If the disk already has an EFI partition, leave it alone. It can be used as is.

Btrfs will use the LUKS1-encrypted system partition /dev/sda2.

+----------------------+----------------------+
| EFI system partition | System partition     |
| unencrypted          | LUKS1-encrypted      |
|                      |                      |
| /efi                 | /                    |
| /dev/sda1            | /dev/sda2            |
|----------------------+----------------------+
Tip: If you created a new ESP, Make sure to format it with FAT32 (mkfs.fat). Do not use vFAT or your system will not boot
Note: /boot will be located on the LUKS1 encrypted system partition. GRUB will be used as the bootloader and decrypt /boot, avoiding an unencrypted /boot partition
Note: Because Btrfs supports swapfile since kernel version 5.0, we will not need a swap partition, saving us some headaches about properly encrypting swap.
Note: It is not possible to use btrfs partitioning as described in Btrfs#Partitionless Btrfs disk when using LUKS. Traditional partitioning must be used, even if it is just to create one partition.

Preparing the system partition

Encrypt and unlock the root partition

see dm-crypt/Device encryption for detailed explanations and other options.

Tip: GRUB's support for LUKS2 is limited; see GRUB#Encrypted /boot for details. Use LUKS1 (cryptsetup luksFormat --type luks1) for partitions that GRUB will need to unlock.
# cryptsetup luksFormat --type luks1 /dev/sda2
# cryptsetup open /dev/sda2 cryptroot

Format the unlocked luks device

see Btrfs#File system on a single device for details.

# mkfs.btrfs -L root /dev/mapper/cryptroot

Create btrfs subvolumes and mount them

Mount the btrfs volume:

# mount /dev/mapper/cryptroot /mnt

Create top-level btrfs subvolumes:

# btrfs subvolume create /mnt/@          # to be mounted at /
# btrfs subvolume create /mnt/@home      # to be mounted at /home
# btrfs subvolume create /mnt/@snapshots # to be mounted at /.snapshots
# btrfs subvolume create /mnt/@var_log   # to be mounted at /var/log

Unmount the btrfs volume:

# umount /mnt

Mount the top level subvolumes:

# mount -o compress=zstd,subvol=@ /dev/mapper/cryptroot /mnt
# mkdir /mnt/home
# mount -o compress=zstd,subvol=@home /dev/mapper/cryptroot /mnt/home
# mkdir /mnt/.snapshots
# mount -o compress=zstd,subvol=@snapshots /dev/mapper/cryptroot /mnt/.snapshots
# mkdir -p /mnt/var/log
# mount -o compress=zstd,subvol=@var_log /dev/mapper/cryptroot /mnt/var/log

Create subvolumes for paths to be excluded from snapshots

This is a good time to create subvolumes for paths you do not want to have snapshots of when taking a snapshot of /. Creating these subvolumes later, when they already contain data will be more difficult.

Since you are still in the live system, where the root (@) subvolume is mounted at /mnt you will need to create the subvolumes at /mnt/<path/to/exclude> You may have to create any parent directories first.

It is recommended to exclude these directories:

# mkdir -p /mnt/var/cache/pacman/
# btrfs subvolume create /mnt/var/cache/pacman/pkg
# btrfs subvolume create /mnt/var/tmp
# btrfs subvolume create /mnt/srv

If you plan to use docker, you may also want to exclude:

# mkdir -p /mnt/var/lib/docker/
# btrfs subvolume create /mnt/var/lib/docker/volumes
# btrfs subvolume create /mnt/var/lib/docker/images

Mount the EFI System Partition (esp)

# mkdir /mnt/efi
# mount /dev/sda1 /mnt/efi
Note: Btrfs snapshots will exclude /efi, since it is not a btrfs file system.

Installation

Warning: Make sure to configure Initramfs and bootloader as described on this page below, otherwise your system will not boot

Now continue following the installation guide starting from the section Installation_guide#Installation to just before the section Installation_guide#Initramfs.

You should now be chrooted into your freshly installed system.

Install additional packages

The Installation_guide installs only the absolute bare minimum. At the very least you need to install btrfs-progs and an editor (for example nano).

# pacman -S btrfs-progs nano

Your life will be easier if you also install:

# pacman -S man-db man-pages bash-completion

Create a new initramfs

Create a keyfile for GRUB to be able to unlock the root partition. See dm-crypt/Device encryption#With a keyfile embedded in the initramfs for details.

# dd bs=512 count=4 if=/dev/random of=/crypto_keyfile.bin iflag=fullblock
# chmod 600 /crypto_keyfile.bin
# chmod 600 /boot/initramfs-linux*
# cryptsetup luksAddKey /dev/sda2 /crypto_keyfile.bin

Add the following parameters to the respective places in /etc/mkinitcpio.conf. See dm-crypt/System configuration#mkinitcpio for detailed information.

BINARIES=(/usr/bin/btrfs)
FILES=(/crypto_keyfile.bin)
HOOKS=(base udev keyboard autodetect keymap consolefont modconf block encrypt filesystems fsck)

Crete the initramfs:

# mkinitcpio -P

Configure and install the boot loader

Install the grub efi binaries to the efi partition:

# grub-install --target=x86_64-efi --efi-directory=efi --bootloader-id=GRUB

Change the GRUB_CMDLINE_LINUX parameter in /etc/default/grub as shown below (using sed to avoid having to manually type the UUID). See GRUB#Encrypted /boot and dm-crypt/System configuration#Using encrypt hook for details.

# uuid=$( blkid -o value /dev/sda2 | head -n 1 )
# sed -i -e "s|\(GRUB_CMDLINE_LINUX=\"\).*\"|\1cryptdevice=UUID=$uuid:cryptroot: crypto=:::: rd.luks.options=discard\"|g" /etc/default/grub

Now open /etc/default/grub in an editor to uncomment:

GRUB_ENABLE_CRYPTODISK=y

while you are there, check that GRUB_CMDLINE_LINUX reads something like:

GRUB_CMDLINE_LINUX="cryptdevice=UUID=12345678-9abcd-ef10-111213141516:cryptroot:enable-discards crypto=:::: rd.luks.options=discard"
Note: I tried without the rd.luks.options=discard kernel parameter, but when I checked, fstrim did not work on my ssd until I added it. I am not sure if the cryptdevice option enable-discards is necessary together with the kernel parameter rd.luks.options=discard, but since fstrim works now, I did not bother to remove it.
Tip: Bonus: add rootflags=rw,noatime,ssd,space_cache,subvolid=256,subvol=/@ to GRUB_CMDLINE_LINUX= in order to set the noatime option for the root filesystem, which improves performance for btrfs and reduces the write operations to the ssd. While you are at it, you can also edit /etc/fstab to replace relatime with noatime for all btrfs filesystems.

Generate the grub config file:

# grub-mkconfig -o /boot/grub/grub.cfg

Create a swap file

See Btrfs#Swap_file for details.

# btrfs subvolume create /swap
# cd /swap
# truncate -s 0 ./swapfile
# chattr +C ./swapfile
# btrfs property set ./swapfile compression none
# fallocate -l 2G swapfile
# chmod 600 ./swapfile
# mkswap ./swapfile
# swapon ./swapfile

Finish up

Make sure you set a root password:

# passwd

Install the appropriate microcode for your processor:

# pacman -S amd-ucode # or 'intel-ucode' for Intel Processors

Reboot:

# reboot