This document is intended to help others achieve a fully encrypted platform, with lowered attack surface for at-rest data. The following text is designed and tailored for the Framework laptop, but should be applicable to most platforms. We will not be covering nested decryption nor the security implications of using TRIM/Discard
, there are numerous documents that cover this thuroughly.
You should be comfortable with filesystem and storage management.
- General understanding of the Linux commandline interface.
- General understanding of LUKS and LVM partitioning.
- General operation of the GRUB bootloader.
- A sense of selfworth and determination that is not easily crushed by hours of trial and error.
- sys-fs/dosfstools
- sys-fs/cryptsetup
In this document we will be configuring an NVMe drive with partions for UEFI, an encrypted boot filesystem, an encrypted LVM volume group, and swap.
-
Create your partition scheme and define your partition usage:
partition
namefs size start end "EFI system partition" fat32 511MB 34s 512MB bootfs ext4[1] 512MB 512MB 1GB swapfs linux-swap(v1) 2GB 1GB 3GB rootfs ext4[1] * 3GB -1s[2] [1] The assignement of this filesystem type doesn't actually matter, as it is undefined when creating a LUKS partition.
[2] This will assign the remaining storage to this partition.
-
Using
parted
, create the partition table and partitions, here we are using the first NVMe disk:parted /dev/nmve0n1 mklabel gpt parted /dev/nmve0n1 mkpart "EFI system partition" fat32 34s 512MB parted /dev/nmve0n1 mkpart bootfs ext4 512MB 1GB parted /dev/nmve0n1 mkpart swapfs "linux-swap(v1)" 1GB 3GB parted /dev/nmve0n1 mkpart rootfs ext4 3GB -1s
-
Toggle the required partition flags, EFI needs
esp
, and the encrypted boot filesystem needsbls_boot
:parted /dev/nmve0n1 toggle 1 esp parted /dev/nmve0n1 toggle 2 bls_boot
-
Create your encrypted boot and root paritions:
NOTE: The usage of the
pbkdf
option is required for the boot partition. As of GRUB v2.06, support of the PBDKF algorithm Argon2id is unsupported without significant code patching. The upstream is said to have the patch applied.cryptsetup --label="crypt_boot" \ -c aes-xts-plain64 -h sha512 \ --pbkdf=pbkdf2 --s 256 \ --use-random luksFormat /dev/disk/by-partlabel/bootfs cryptsetup luksDump /dev/disk/by-partlabel/bootfs | grep "^UUID" cryptsetup --label="crypt_root" \ -c aes-xts-plain64 -h sha512 \ --s 256 \ --use-random luksFormat /dev/disk/by-partlabel/rootfs cryptsetup luksDump /dev/disk/by-partlabel/rootfs| grep "^UUID"
Record the UUIDs for
rootfs
andbootfs
, as we will need them later.
As we are operating on an NVMe SSD, we can optionally use some options that are more effective and efficient. By enabling no-read-workqueue
and no-write-workqueue
flags, we can help negate some of the cpu work load from encryption.
SECUIRTY NOTE: The usage of allow-discards
flag has security implecations. Understand them and use them at your own risk.
cryptsetup open --persistent \
--allow-discards \
--perf-no_read_workqueue --perf-no_write_workqueue \
/dev/disk/by-partlabel/bootfs luks_boot
cryptsetup open --persistent \
--allow-discards \
--perf-no_read_workqueue --perf-no_write_workqueue \
/dev/disk/by-partlabel/rootfs luks_root
This is outside of the scope of this document. Apply vgcreate
to /dev/mapper/luks_root
, and create your required logical volumes for your storage needs.
-
Format the UEFI partition.
NOTE that we are using the
mkfs.fat
utility NOTmkfs.vfat
. Many UEFI loaders are very particular about the exact type of FAT32 partition.mkfs.fat -F 32 "/dev/disk/by-partlabel/EFI\x20system\x20partition"
-
Format the
luks_boot
partition.mkfs.ext4 -I 256 /dev/mapper/luks_boot
We use the
-I 256
option as the128
value is deprercating soon. -
Continue formating the rest of the system logical volumes.
- Nothing unusual here, mount up the root filesystem partitions, and new
luks_boot
partition to/boot
. - Create the path
/boot/efi
for the UEFI partition, and mount it.
Continue with your system configuration, kernel building. You do you.
This is covered in other tutorials, but here is it anyways:
grub-install --target=x86_64-efi \
--boot-directory=/boot \
--efi-directory=/boot/efi /dev/nvme0n1
Create the UEFI file tree structure.
mkdir - /boot/efi/EFI/{gentoo,grub}
In the next step we will build a custom boot image, but before we do that we need to setup the built-in configuration stub file. GRUB EFI images build in a config as the first stage, and follow it with the config that lives in the EFI partition. This can lead to some confusion on why, for example, you would get prompted twice for a passphrase even if you have entered it correctly the first time. We will use this built-in as a preperation to load the bare minimum to function. In this case, we setup the graphics terminal prior to handing off to the grub config file on the UEFI partition.
/boot/efi/EFI/grub/grub.cfg.built-in
insmod part_gpt
insmod ext2
insmod fat
insmod configfile
insmod video
insmod efi_gop
insmod efi_uga
insmod video_fb
loadfont unicode
set gfxmode=1024x768
insmod gfxterm
set locale_dir=$prefix/locale
set lang=en_US
insmod gettext
terminal_output gfxterm
At a minimum insert: part_gpt
, ext2
, fat
, configfile
This is the file that grubx64.efi
will access AFTER running the required built-in config. At the creation of this Gist, if this content is located in the built-in file GRUB will ask for the passphrase twice.
/boot/efi/EFI/grub/grub.cfg
insmod crypto
insmod cryptodisk
insmod luks
insmod luks2
insmod gcry_sha256
insmod gcry_sha512
insmod gcry_crc
insmod pbkdf2
insmod normal
cryptomount (hd0,gpt2)
configfile (crypto0)/grub/grub.cfg
normal
Next we need to create a custom UEFI boot image to handle our lack of valid boot partition, and get us to a valid GRUB partition. The default image does not contain enough built-in modules (nor does it include when grub-install
is run) to detect or read the UEFI partition, and is designed to shim to an unencrypted boot partition. Therefore we need to front load the all the modules to do the following: read the UEFI partition, GRUB configuration file, and decrypt the boot partition. Notice we have defined the built-in config for in the variable EFI_GRUB_CFG
.
update-efi-image
BITS=64
ARCH="x86_64-efi"
RELEASE="gentoo"
EFI_GRUB_ROOT="/EFI/grub"
EFI_BOOT_IMG="/EFI/${RELEASE}/grubx${BITS}.efi"
EFI_PATH="/boot/efi"
EFI_GRUB_CFG="${EFI_PATH}${EFI_GRUB_ROOT}/grub.cfg.built-in"
EFI_IMAGE="${EFI_PATH}${EFI_BOOT_IMG}"
VID_MODS=( video efi_gop efi_uga video_fb gfxterm gettext )
CRYPT_MODS=( crypto cryptodisk luks2 gcry_sha256 gcry_sha512 gcry_crc pbkdf2 )
FS_MODS=( part_gpt fat ext2 )
MODULES=( normal configfile ${VID_MODS[@]} ${CRYPT_MODS[@]} ${FS_MODS[@]} )
MKIMG_BIN=`which grub-mkimage`
MKIMG_OPTS=( -O ${ARCH} -c ${EFI_GRUB_CFG} -p ${EFI_GRUB_ROOT} -o ${EFI_IMAGE} ${MODULES[@]} )
$MKIMG_BIN ${MKIMG_OPTS[@]}
If you elect for an early graphical terminal, you will need a few extra files in your UEFI partition. Copy the following to /boot/efi/EFI/grub
:
/boot/grub/fonts
/boot/grub/locale
Optional: For development and testing as they will only be available by editing /EFI/grub/grub.cfg
. While booting in this mode, there is no access to GRUB rescue
.
/boot/grub/x86_64-efi
In the boot order, once we have loaded the initramfs and exited GRUB the encryption on the boot partition is release. Therefore we may need to add it back in to unlock so we can do system updates. There are options available for fancy automatic decryption with nested keys, but we're just going to record the the entry for now, and you can spend time on that later.
SECUIRTY NOTE: The usage of allow-discards
flag has security implecations. Understand them and use them at your own risk.
/etc/crypttab
luks_bootfs UUID={luks_boot_UUID} none luks,allow-discards,no-read-workqueue,no-write-workqueue
Duplicate this in /etc/crypttab.initramfs
for completionary sake as some initramfs generators require this information, and add the following line:
/etc/crypttab.initrams
luks_bootfs UUID={luks_boot_UUID} none luks,allow-discards,no-read-workqueue,no-write-workqueue
luks_rootfs UUID={luks_root_UUID} none luks,allow-discards,no-read-workqueue,no-write-workqueue
As we start to draw to a close, we need to make sure GRUB knows what to do with an encrypted root partition, and logical volumes when generating the grub.cfg
file. Modify the GRUB_CMDLINE_LINUX_DEFAULT
line with the following, at a minimum you will need the doluks and dolvm
, rd.luks.uuid
and crypt_root
entries for a valid system.
GRUB_CMDLINE_LINUX_DEFAULT="real_root=/dev/{VGname}/root
doluks dolvm rd.luks.uuid=luks-{luks_rootfs_UUID}
crypt_root=UUID={luks_rootfs_UUID}
rd.lvm.lv={VGname}/root {any additional LVs to activate}
At this point you can generate your GRUB configuration file. Everything is in place now to allow you to boot a fully encrypted system, and allow it to mount everything.
grub-mkconfig -o /boot/grub/grub.cfg