Complete linux system encryption

A quick guide on how to encrypt a complete Gentoo Linux system. By now I have encrypted all my laptops and my little home server. This blog is just a reminder on how to do it, from A to Z. Perhaps it is beneficial for others too.

The objective is all parts of the systems encrypted, including /boot, and swap, and to enter the decryption password only once at boot.

This will be a Gentoo linux based system, making use of an UEFI boot sequence, and GRUB boot loader, with OpenRC as init system. Btrfs will be used as file system.

/dev/sda is used as the the root disk.

Disk partitioning

Make sure to boot from a UEFI capable USB stick, e.g. from the minimal installation CD.

Create a new GTP disk label and the following partitions:

NAME           SIZE     TYPE              Purpose
sda
├─sda1    256 MB  EFI System        Boot loader
├─sda2     16 GB  Linux swap        Encrypted swap
└─sda3      rest  Linux filesystem  System disk

The size of the swap partition should be twice the available RAM.

Format the EFI partition

The EFI partition /dev/sda1 is to be formatted with VFAT32:

# mkfs.vfat -F 32 -n EFI /dev/sda1

Encrypt the root file system and format it

Determine first the UUID of the root disk /dev/sda3 and use that UUID to make a decrypted device at /dev/mapper/luks-{UUID}, and create a subvolume gentoo for the root file system:

# LUKS_ID=$(blkid -o value /dev/sda3 | head -1)
# cryptsetup luksFormat --type luks1 /dev/sda3 
# cryptsetup luksOpen  /dev/sda3 "luks-${LUKS_ID}"
# mkfs -t btrfs -L rootfs /dev/mapper/luks-${LUKS_ID}
# btrfs subvol create /dev/mapper/luks-${LUKS_ID}/gentoo

Keep note of the UUID of the root disk, stored in ${LUKS_ID}. It is going to be needed later.

Install Gentoo as per normal on /dev/mapper/luks-${LUKS_ID}

Mount the "gentoo" subvolume of the crypto disk on /mnt/gentoo,, and mount the EFI partion /dev/sda1 on its /boot/efi directory:

# mount -o subvol=gentoo /dev/mapper/luks-${LUKS_ID} /mnt/gentoo
# mkdir/mnt/gentoo/boot/efi
# mount /dev/sda1 /mnt/gentoo/boot/efi

Download stage3 and unpack it in /mnt/gentoo.

And then chroot into the new environment:

# cp --dereference /etc/resolv.conf /mnt/gentoo/etc/
# mount --types proc /proc /mnt/gentoo/proc
# mount --rbind /sys /mnt/gentoo/sys
# mount --rbind /dev /mnt/gentoo/dev
# mount --bind /run /mnt/gentoo/run
# chroot /mnt/gentoo /bin/bash
# source /etc/profile
# export PS1="(chroot) ${PS1}"

And then continue installing Gentoo as per the handbook.

Make sure to install at least the following packages:

Create a keyfile for the rootfs

A keyfile on encrypted storage to be included in the initramfs, which is also on encrypted storage.

# mkdir /etc/crypt
# dd if=/dev/urandom of=/etc/crypt/key.sda3 bs=1 count=4096`
# cryptsetup luksAddKey /dev/sda3 /etc/crypt/key.sda3

Kernel installation

The easiest and quickest way is to use the Gentoo distribution kernel.

Gentoo now comes with sys-kernel/installkernel which can:

  • install the kernel in /boot
  • create an initramfs using dracut
  • generate GRUB's configuration file at /boot/grub/grub.cfg.

It requires some settings and USE flags for it all to work.

Create /etc/portage/package.use/installkernel with the following content, telling installkernel to use grub and dracut:

sys-kernel/installkernel grub dracut

Configure dracut with a file /etc/dracut.conf, telling it which modules to load and where the key for the root disk is:

add_dracutmodules+=" crypt btrfs dm "
install_items+=" /etc/crypt/key.sda3 "

Configure grub in /etc/default/grub, specifying that it needs to open an encrypted disk, load the needed modules, and some more linux command line parameters::

GRUB_DISABLE_SUBMENU=y
GRUB_ENABLE_CRYPTODISK=y
GRUB_PRELOAD_MODULES="luks luks2 geli cryptodisk btrfs"
GRUB_CMDLINE_LINUX="rd.hostonly=1 rootfstype=btrfs rd.luks.allow-discards rd.retry=20 rd.timeout=120 rd.luks=1 rd.luks.uuid=${LUKS_ID} rd.luks.key=/etc/crypt/key.sda3:/ "

Finally emerge sys-kernel/gentoo-kernel or sys-kernel/gentoo-kernel-bin.

If all went well there should be kernel with an initramfs in /boot, and a grub config file in /boot/grub/grub.cfg.

Install the boot loader on the EFI partition

# grub-install --efi-directory=/boot/efi

Enable encrypted swap

Encrypted swap is necessary for a properly secured system. It is easy to configure using OpenRC.

Create a file /etc/conf.d/dmcrypt as follows:

swap=swap-sda2
source='/dev/sda2'

Add dmcrypt to the boot level start up processes:

# rc-config add dmcrypt boot

This will freshly encypt /dev/sda2 on boot, and make it available as /dev/mapper/swap-sda2. It will also place a swap file system on top of it.

Update fstab

Add the following to /etc/fstab to mount the relevant partitions on boot:

/dev/sda1 /boot/efi vfat noauto 1 2
/dev/mapper/luks-${LUKS_ID} / btrfs noatime,subvol=gentoo 0 1
/dev/mapper/swap-sda2 none swap sw,pri=10 0 0

Remember to replace ${LUKS_ID} with the UUID for the encrypted sda3 partition.

Reboot your system

If all went well then:

  • The EFI boot loader will call GRUB
  • GRUB will then present you with the password to open /dev/sda3
  • Once /dev/sda3 is opened, GRUB show its menu, and then boot using the dracut initramfs
  • Because GRUB cannot pass on the opened device, the initramfs opens the it again using the key file prior to hading over to the linux kernel.

Enable hibernate on encrypted swap

Optionally, when using a laptop, it may be useful to enable hibernation, with the memory image written to the encrypted swap partition.

This requires the major and minor device number to be written to /sys/power/resume in the format "MAJOR:MINOR".

An easy way to do this is by placing a small script to be called from OpenRC's local service.

Put the following in a file /etc/local.d/70-setup-hibernate-partition.start and make it executable:

#!/bin/bash
# Sets up the hiberntate partition by finding the swap partition name,
# and then obtaining the major:minor device id of the swap partition
# and then finally writing the major:minor to /sys/power/resume
#
# Only works when there is only one swap partition

DEV=$(swapon --show=NAME --noheadings)
MAJMIN=$(lsblk ${DEV} -o MAJ:MIN -n)
echo ${MAJMIN} > /sys/power/resume

Execute the script and verify if the contents of /sys/power/resume is something like 252:1.

Conclusion

That's it. A fully encrypted system.

Pages