User:Screenager/install/laptop rootfsencryption detached luks header

From Gentoo Wiki
Jump to:navigation Jump to:search

Introduction

Why

Gentoo allows for extreme customization starting with the installation process. This guide is meant to explain an advanced encrypted installation using logical volume management underneath, aiming to extend the 'Preparing the disks' section in the official handbook.

Prerequisites

Block Devices

Important
Without understanding block devices fully, it will be hard to follow this guide. There will be encapsulating of abstraction layers. If this sounds scary, careful reading of the following articles is advised.

It is important to understand block devices. The official handbook offers information for that: Link

dm-crypt

This software will be responsible for creating an encrypted container on your block device, which in itself will be treated as just another block device when mounted. More information here: Link

LVM - Logical Volume Manager

This will add more block device abstraction layers. Again it is advised to read the wiki article beforehand: Link

Secure Wipe

This guide will be written for installation on a SSD, therefore a secure wipe beforehand is advised: Link


Preparing the disks

Example Setup:

Important
A detached Header placed on the same physical drive as the luks container is no security improvement, but there is also no downside to just always use detached headers, even if they are not placed on a removable device.

Output generated with lsblk -o NAME,PARTLABEL,SIZE,FSTYPE,TYPE,MOUNTPOINT

CODE
NAME           PARTLABEL   SIZE FSTYPE      TYPE  MOUNTPOINT
sda                      465,8G             disk  
|-sda1         efi         256M vfat        part  /mnt/gentoo/efi
|-sda2         bootx       768M ext4        part  /mnt/gentoo/boot
`-sda3         luks      464,8G             part  
  `-luks                 464,8G LVM2_member crypt 
    |-vg1-swap              16G swap        lvm   [SWAP]
    `-vg1-root           448,5G ext4        lvm   /mnt/gentoo
Note
Due to the detached Header lsblk is showing a partition without a filesystem for sda3

By now Networking should be completed and all Prerequisites should be understood. First identify your block devices, going forward this guide will use

root #lsblk -o NAME,PARTLABEL,SIZE,FSTYPE,TYPE,MOUNTPOINT
NAME   PARTLABEL   SIZE FSTYPE TYPE MOUNTPOINT
sda              465,8G        disk
Note
If the device got erased just now, it might be necessary to run
root #partprobe /dev/sda
before lsblk will show the changes

Creating the partitions

Invoke fdisk:

root #fdisk /dev/sda
Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xba70857e.

Command (m for help):

Next create a GPT partition table and a 256MB ESP partition:

Command (m for help):g
Created a new GPT disklabel (GUID: 226B0C64-4F00-4A44-86B3-D897AB1F5009).
Command (m for help):n
Partition number (1-128, default 1): 1
First sector (2048-976773134, default 2048): 
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-976773134, default 976773119): +256M

Created a new partition 1 of type 'Linux filesystem' and of size 256 MiB.
Command (m for help):t
Selected partition 1
Partition type or alias (type L to list all): 1
Changed type of partition 'Linux filesystem' to 'EFI System'.

Now create a 768MB extended Boot Partition:

Command (m for help):n
Partition number (2-128, default 2): 
First sector (526336-976773134, default 526336): 
Last sector, +/-sectors or +/-size{K,M,G,T,P} (526336-976773134, default 976773119): +768M

Created a new partition 2 of type 'Linux filesystem' and of size 768 MiB.
Command (m for help):t
Partition number (1,2, default 2): 
Partition type or alias (type L to list all): 136

Changed type of partition 'Linux filesystem' to 'Linux extended boot'.

Finnally create a partition for the rest of the drive:

Note
Without activating the SSD discard function it may be beneficial to leave 10-15% of unpartitioned space
Command (m for help):n
Partition number (3-128, default 3): 
First sector (2099200-976773134, default 2099200): 
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2099200-976773134, default 976773119): 

Created a new partition 3 of type 'Linux filesystem' and of size 464.8 GiB.

Write the changes with:

Command (m for help):w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Now format the ESP partitions with fat32 and the extended Boot partition with ext4:

root #mkfs.vfat -F 32 /dev/sda1
root #mkfs.ext4 /dev/sda2

Partitionlabels may be set with parted or Gparted when working from a GUI.

root #parted
GNU Parted 3.6
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) name 2 'bootx'

Finnaly make shure everything is how it should be:

root #lsblk -o NAME,PARTLABEL,SIZE,FSTYPE,TYPE,MOUNTPOINT
NAME   PARTLABEL        SIZE FSTYPE TYPE MOUNTPOINT
sda                   465.8G        disk 
├─sda1 efi              256M vfat   part 
├─sda2 bootx            768M ext4   part 
└─sda3 cryptContainer 464.8G        part 

Cryptsetup

Run

root #cryptsetup benchmark

to make shure everything is ready to continue. First, temporarily mount the extended boot partition to save the header there, create a temp folder:

root #mkdir /mnt/tmp

and mount the partition:

root #mount /dev/sda2 /mnt/tmp

Now run

root #cryptsetup -c aes-xts-plain64 -s 512 -y luksFormat /dev/sda3 --header /mnt/tmp/header.img
Note
It may not be unwise to use a rather simple password in the beginning. It is possible to destroy the first keyslot later and use a more secure password once everything is running. Take special care in not copying the header until it is fully secured.
Warning
If the header image file is lost all data will be unrecoverable

To instantly check if everything worked run:

root #cryptsetup luksDump /dev/sda3 --header /mnt/tmp/header.img

continue with opening and mapping the luks container:

root #cryptsetup luksOpen /dev/sda3 lukscont --header /mnt/tmp/header.img

this will create the lukscont block device in /dev/mapper/
Now it is save to unmount the extended boot partition again:

root #umount /mnt/tmp

and

root #rmdir /mnt/tmp

to clean up. lsblk should now show the new logical block device:

root #lsblk -o NAME,PARTLABEL,SIZE,FSTYPE,TYPE,MOUNTPOINT
NAME         PARTLABEL        SIZE FSTYPE TYPE  MOUNTPOINT
sda                         465.8G        disk  
├─sda1       efi              256M vfat   part  
├─sda2       bootx            768M ext4   part  
└─sda3       cryptContainer 464.8G        part  
  └─lukscont                464.8G        crypt 

LVM Setup

With LVM it will be easily possible to encrypt and decrypt multiple partitions with a single password/keyfile. LVM will also allow easy extending or shrinking of partitions as well as percentage based allocation. Start by creating a pysical volume:

root #pvcreate /dev/mapper/lukscont

follwing by creating a volume group within the just created pysical volume

root #vgcreate vg1 /dev/mapper/lukscont

this will create the volume group vg1. Next it is time to create logical volumes for a swap and root partition.

root #lvcreate --size 16G --name swap vg1

and

root #lvcreate --size 100G --name root vg1
Note
It will be very easy to create more partitions later or extent the root partition to the full size of the volume group

Next, formate and enable the swap partition:

root #mkswap /dev/vg1/swap
root #swapon /dev/mapper/vg1-swap

check with:

root #swapon -d

Format the root partition and prepare the filesystem:

root #mkfs.ext4 /dev/vg1/root
root #mkdir /mnt/gentoo
root #mount /dev/vg1/root /mnt/gentoo/
root #mkdir /mnt/gentoo/efi
root #mkdir /mnt/gentoo/boot
root #mount /dev/sda1 /mnt/gentoo/efi/
root #mount /dev/sda2 /mnt/gentoo/boot/

which concludes the disk preparation and filesystem setup. Perform a final check with lsblk:

root #lsblk -o NAME,PARTLABEL,SIZE,FSTYPE,TYPE,MOUNTPOINT
NAME           PARTLABEL        SIZE FSTYPE      TYPE  MOUNTPOINT
sda                           465.8G             disk  
├─sda1         efi              256M vfat        part  /mnt/gentoo/efi
├─sda2         bootx            768M ext4        part  /mnt/gentoo/boot
└─sda3         cryptContainer 464.8G             part  
  └─lukscont                  464.8G LVM2_member crypt 
    ├─vg1-swap                   16G swap        lvm   [SWAP]
    └─vg1-root                  100G ext4        lvm   /mnt/gentoo

Continue with the next part of the handbook until 'Configuring the bootloader'

Configuring the bootloader

Warning
Dracut and detached headers without using systemd seem to be broken as of 2023. If using this configuration the system won't boot without user intervention

Remember to emerge LVM and dm-crypt too, while chrooted and add them to OpenRC. Then beginn by installing grub:

root #emerge --ask sys-boot/grub

and install it to UEFI with:

root #grub-install --target=x86_64-efi --efi-directory=/efi

generate a config for grub to boot

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

Next it is time to configure dracut

Note
It might be a good idea to specify a keymap when facing a password input
FILE /etc/dracut.conf
add_dracutmodules+=" dm crypt lvm resume "
hostonly=yes
kernel_cmdline="rd.vconsole.keymap=<your_keymap_here> rd.vconsole.unicode"

and rebuild the initramfs from chroot with specifing the kernel after passing empty parameters:

root #dracut "" 6.1.67-gentoo-dist --force

If the system is now rebooted it will propably drop to dracuts rescue shell where the lukscontainer will need to be mounted (remember to mount and afterwards unmount your partition with the header)

dracut:/#cryptsetup luksOpen /dev/sda3 lukscont --header /mnt/tmp/header.img

and then activate the lvm volume group with

dracut:/#lvm vgchange -ay

exit the rescue shell with

dracut:/#exit

and the system should boot.

Modifying Dracut

Dracut is build with customization in mind, it not only allows but encourages users to hook into any stage of it's bootstrap process. Check the official documentation with:

root #man dracut.modules

At this point it is clear that a script needs to be installed into dracut that will automate what we did before during the rescue shell. Start by creating a new folder:

root #mkdir /usr/lib/dracut/modules.d/92local-root

For a minimal example two files within that folder need to be created:

FILE /usr/lib/dracut/modules.d/92local-root/module-setup.sh
#!/bin/bash
check(){
    return 0
}
install(){
    inst_hook initqueue/settled 92 "$moddir/mount-root.sh"
}

this file will tell dracut to always install the specified script and where in the bootstrap process it will be inserted into the loop. The actual script will be:

FILE /usr/lib/dracut/modules.d/92local-root/mount-root.sh
#!/bin/bash

#This function will get looped in dracuts initqueue
mount_local_root(){

    if [ ! -b /dev/vg1/root ]                                        #Check if root already is mountable
    then
        mkdir /tmp/mnt
        mount /dev/sda2 /tmp/mnt                                     #mount the header partition              
        dmesg -D                                                     #disables the kernel console output in order to not clutter the screen
        read -s -p "Enter Password:" pword
        echo $pword | cryptsetup luksOpen /dev/sda3 lukscont --header /tmp/mnt/header.img
        unset pword                                                  # we do NOT want our password to stay somewhere in memory
        if [ ! -b  /dev/mapper/lukscont ]                                #check if unlock succeeded
        then
            echo "YOU DIDN'T SAY THE MAGIC WORD"
            dmesg -E
            umount /tmp/mnt
        else
            lvm pvscan
            lvm vgscan
            lvm lvscan
            lvm vgchange -ay
            dmesg -E
            umount /tmp/mnt
        fi
    fi


}
mount_local_root

This script will automate the boot process and allow dracut to mount the root partition and continue with booting after entering the password. Finally rebuild the initramfs with

root #dracut "" 6.1.67-gentoo-dist --force

after reboot it should be now possible to boot as expected.