Full Disk Encryption From Scratch Simplified

From Gentoo Wiki
Jump to:navigation Jump to:search

This article discusses several aspects of using dm-crypt for full disk encryption with LVM (with some notes for SSD) for daily usage from scratch.

Most of details can also be found in the LUKS-LVM filesystem (Sakaki's Unofficial Install Guide).

Disk preparation

This example will use GPT as disk partition schema and GRUB as boot loader. parted will be used as the partitioning tool though any valid tool will work.

Note
For more information about GPT and EFI, see Disks (AMD64 Handbook)

Create partitions

Partition schema for a common desktop system is as following. Headless systems get along with a smaller root partition, e.g. 20-30GiB.

--------------------------------------------------------------------------------
/dev/sdX
|--> GRUB BIOS                       2   MB       no fs       GRUB loader itself
|--> /boot                 boot      512 MB       fat32       GRUB and kernel
|--> LUKS encrypted                  100%         encrypted   encrypted block device
     |-->  LVM             lvm       100%                  
           |--> /          root      40  GB       ext4        root filesystem
           |--> /var       var       40  GB       ext4        var files
           |--> /home      home      100%         ext4        user files

To create GRUB BIOS, issue the following command:

root@localhost #parted -a optimal /dev/sdX

Set the default units to mebibytes:

(parted)unit mib

Create a GPT partition table:

(parted)mklabel gpt

Create the BIOS partition:

(parted)mkpart primary 1 3
(parted)name 1 grub
(parted)set 1 bios_grub on

Create boot partition. This partition will contain GRUB files, the plain (unencrypted) kernel and the kernel initrd:

(parted)mkpart primary fat32 3 515
(parted)name 2 boot
(parted)set 2 BOOT on
(parted)mkpart primary 515 -1
(parted)name 3 lvm
(parted)set 3 lvm on

Everything is done, exit parted:

(parted)quit

Create boot filesystem

Create a filesystem for /dev/sdX2, that will contain GRUB and kernel files. This partition is read by UEFI BIOS. Most motherboards can read only a FAT32 filesystem:

root@localhost #mkfs.vfat -F32 /dev/sdX2

Prepare encrypted partition

In the next step, configure dm-crypt for /dev/sdX3:

Note
For Ubuntu live cd, execute this command
root@localhost #modprobe dm-crypt

Encrypt LVM partition /dev/sdX3 with LUKS:

root@localhost #cryptsetup luksFormat /dev/sdX3
Note
Only specify arguments like -c <cipher> or -s <keysize> if you are certain that it improves security beyond the sane defaults. Continue by typing in UPPERCASE YES
Note
The following message can be ignored:
CODE
device-mapper: remove ioctl on temporary-cryptsetup-nnnnnn failed: Device or resource busy

Create LVM inside encrypted block

LVM creation

Open the encrypted device:

root@localhost #cryptsetup luksOpen /dev/sdX3 lvm
Note
For more information about LVM, see the dedicated article.

Create the LVM structure for partition mapping (/root, /var, and /home):

Crypt physical volume group:

root@localhost #lvm pvcreate /dev/mapper/lvm

Create volume group vg0:

root@localhost #vgcreate vg0 /dev/mapper/lvm

Create logical volume for /root filesystem:

root@localhost #lvcreate -L 25G -n root vg0

Create logical volume for /var filesystem:

root@localhost #lvcreate -L 40G -n var vg0

Create logical volume for /home filesystem:

root@localhost #lvcreate -l 100%FREE -n home vg0

File Systems

Build ext4 filesystem on each logical volume:

root@localhost #mkfs.ext4 /dev/mapper/vg0-root
root@localhost #mkfs.ext4 /dev/mapper/vg0-var
root@localhost #mkfs.ext4 /dev/mapper/vg0-home

Gentoo installation

Create mount point for permanent Gentoo:

root@localhost #mkdir /mnt/gentoo

Mount the root filesystem from the encrypted LVM partition:

root@localhost #mount /dev/mapper/vg0-root /mnt/gentoo

Create mount point for permanent Gentoo /var:

root@localhost #mkdir /mnt/gentoo/var

Mount var from encrypted LVM partition:

root@localhost #mount /dev/mapper/vg0-var /mnt/gentoo/var

And switch into /mnt/gentoo:

root@localhost #cd /mnt/gentoo
Note
If you are making changes to the home partition (like adding a user) in the chroot
root@localhost:/#mkdir /mnt/gentoo/home
root@localhost:/#mount /dev/mapper/vg0-home /mnt/gentoo/home/

rootfs install

Stage 3 install

Download the stage3 to /mnt/gentoo from Gentoo mirrors.

For example:

Extract the downloaded archive:

root@localhost:/mnt/gentoo#tar xvjpf stage3-*.tar.bz2 --xattrs --numeric-owner

Or for the currently used (2022) xz compression use:

root@localhost:/mnt/gentoo#tar xvJpf stage3-amd64-desktop-systemd-20220102T170545Z.tar.xz --xattrs --numeric-owner
Note
For more details, see Handbook:AMD64/Installation/Stage

Configuring compile options

Open /mnt/gentoo/etc/portage/make.conf with nano and setup required flags. See Stages (AMD64 Handbook) article.

Repos configuration

root@localhost:/mnt/gentoo#mkdir /mnt/gentoo/etc/portage/repos.conf
root@localhost:/mnt/gentoo#cp /mnt/gentoo/usr/share/portage/config/repos.conf /mnt/gentoo/etc/portage/repos.conf/gentoo.conf

Chroot prepare

Copy DNS info:

root@localhost:/mnt/gentoo#cp /etc/resolv.conf /mnt/gentoo/etc/resolv.conf

Mount all required filesystems into chroot:

root@localhost:/mnt/gentoo#mount --types proc /proc /mnt/gentoo/proc
root@localhost:/mnt/gentoo#mount --rbind /sys /mnt/gentoo/sys
root@localhost:/mnt/gentoo#mount --make-rslave /mnt/gentoo/sys
root@localhost:/mnt/gentoo#mount --rbind /dev /mnt/gentoo/dev
root@localhost:/mnt/gentoo#mount --make-rslave /mnt/gentoo/dev
root@localhost:/mnt/gentoo#mount --bind /run /mnt/gentoo/run
root@localhost:/mnt/gentoo#mount --make-slave /mnt/gentoo/run

Mount shm filesystem:

root@localhost:/mnt/gentoo#test -L /dev/shm && rm /dev/shm && mkdir /dev/shm
root@localhost:/mnt/gentoo#mount -t tmpfs -o nosuid,nodev,noexec shm /dev/shm
root@localhost:/mnt/gentoo#chmod 1777 /dev/shm

Enter chroot:

root@localhost:/mnt/gentoo#chroot /mnt/gentoo /bin/bash
root@localhost:/mnt/gentoo#source /etc/profile

And run:

root@localhost:/#export PS1="(chroot) $PS1"

Mounting the boot partition:

(chroot) root@localhost:/#mount /dev/sdX2 /boot

Synchronize ebuild repository:

(chroot) root@localhost:/#emerge-webrsync

Choose and install correct profile:

(chroot) root@localhost:/#eselect profile list

Select profile:

(chroot) root@localhost:/#eselect profile set X

Setup the correct timezone:

(chroot) root@localhost:/#echo Europe/Kiev > /etc/timezone
(chroot) root@localhost:/#emerge --config sys-libs/timezone-data

Configure locales:

(chroot) root@localhost:/#nano -w /etc/locale.gen
(chroot) root@localhost:/#locale-gen

Set default locale:

(chroot) root@localhost:/#eselect locale list
(chroot) root@localhost:/#eselect locale set 1

Update the environment:

(chroot) root@localhost:/#env-update && source /etc/profile

Configure fstab

For consistent setup of the required partition, use the UUID identifier.

Run blkid and see partition IDs:

(chroot) root@localhost:/#blkid
/dev/sdb1: UUID="4F20-B9DB" TYPE="vfat" PARTLABEL="grub" PARTUUID="70b1627b-57e7-4559-877a-355184f0ab9d"
/dev/sdb2: UUID="DB1D-89C5" TYPE="vfat" PARTLABEL="boot" PARTUUID="b2a61809-4c19-4685-8875-e7fdf645eec5"
/dev/sdb3: UUID="6a7a642a-3262-4f87-9540-bcd53969343b" TYPE="crypto_LUKS" PARTLABEL="lvm" PARTUUID="be8e6694-b39c-4d2f-9f42-7ca455fdd64f"
/dev/mapper/lvm: UUID="HL32bg-ZjrZ-RBo9-PcFM-DmaQ-QbrC-9HkNMk" TYPE="LVM2_member"
/dev/mapper/vg0-root: UUID="6bedbbd8-cea9-4734-9c49-8e985c61c120" TYPE="ext4"
/dev/mapper/vg0-var: UUID="61e4cc83-a1ee-4190-914b-4b62b49ac77f" TYPE="ext4"
/dev/mapper/vg0-home: UUID="5d6ff087-50ce-400f-91c4-e3378be23c00" TYPE="ext4"

Edit /etc/fstab and setup correct filesystem:

FILE /etc/fstab
# <fs>                                          <mountpoint>    <type>          <opts>          <dump/pass>
UUID=DB1D-89C5                                  /boot           vfat            noauto,noatime  1 2
UUID=6bedbbd8-cea9-4734-9c49-8e985c61c120       /               ext4            defaults        0 1
UUID=61e4cc83-a1ee-4190-914b-4b62b49ac77f       /var            ext4            defaults        0 1
UUID=5d6ff087-50ce-400f-91c4-e3378be23c00       /home           ext4            defaults        0 1
# tmps
tmpfs                                           /tmp            tmpfs           size=4G         0 0

Configuring the Linux kernel

Make sure to enable USE=lvm for sys-fs/lvm2:

FILE /etc/portage/package.use
# Enable support for the LVM daemon and related tools
sys-fs/lvm2 lvm

Install kernel, genkernel, and cryptsetup packages:

(chroot) root@localhost:/#emerge sys-kernel/gentoo-sources
(chroot) root@localhost:/#emerge sys-kernel/genkernel
(chroot) root@localhost:/#emerge sys-fs/cryptsetup
(chroot) root@localhost:/#emerge sys-fs/lvm2

Build genkernel:

(chroot) root@localhost:/#genkernel --luks --lvm --no-zfs all

Modern processors, like Intel Core or AMD Ryzen, support AES-NI instruction set. AES-NI significantly improves encryption/decryption performance. To enable AES-NI support in the kernel:

KERNEL AES-NI cipher algorithm
--- Cryptographic API
   <*>   AES cipher algorithms (AES-NI)
Warning
When using a LUKS passphrase, double check that the kernel configuration has a usable framebuffer configuration or else ensure text-only GRUB with text-only payload and no gfxterm. Otherwise the LUKS passphrase prompt may not be visible. Consult the graphic driver's setup. It may also be necessary to fix Kernel's keymap if the passphrase contains special characters.

Optionally:

KERNEL SHA-256 with NI instructions
--- Cryptographic API
   <*>   SHA1 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)                                                                          │ │  
   <*>   SHA256 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)
Note
To build only initramfs:
(chroot) root@localhost:/#genkernel --luks --lvm initramfs

Install GRUB2

(chroot) root@localhost:/#echo "sys-boot/grub:2 device-mapper" >> /etc/portage/package.use/sys-boot
(chroot) root@localhost:/#emerge -av grub
FILE /etc/default/grub
GRUB_CMDLINE_LINUX="dolvm crypt_root=UUID=(REPLACE ME WITH sdb3 UUID from above)"

Don't forget to change "(REPLACE ME WITH sdb3 UUID from above)" to the actual value.

Mount boot:

(chroot) root@localhost:/#mount /boot

Install GRUB with EFI:

Note
This configuration utilizes a combined boot/UEFI partition. Remember that in this configuration, the UEFI information is referenced by /boot/efi/... and not /boot/efi/efi/...
(chroot) root@localhost:/#grub-install --target=x86_64-efi --efi-directory=/boot
Note
Upon receiving the message "Could not prepare Boot variable: Read-only file system", try running:
(chroot) root@localhost:/#mount -o remount,rw /sys/firmware/efi/efivars
Note
For some old motherboards for GRUB run this command:
(chroot) root@localhost:/#mkdir -p /boot/efi/boot
(chroot) root@localhost:/#cp /boot/efi/gentoo/grubx64.efi /boot/efi/boot/bootx64.efi

Make sure that /etc/default/grub is configured correctly. Especially with UEFI GRUB and kernel might use different framebuffer drivers. Generate GRUB configuration file:

(chroot) root@localhost:/#grub-mkconfig -o /boot/grub/grub.cfg
Note
When using a LUKS passphrase and there is no visible prompt after loading the initramfs, try typing the passphrase. If this continues loading try GRUB without gfxterm/ in text-only mode. Depending on the BIOS it might help to boot legacy first to check if there's a prompt at all.

Finalizing

While in the chroot setup, it is important to remember to set the root password before rebooting:

(chroot) root@localhost:/#passwd

After the install is complete, add the LVM service to boot. If this is not done, at the very least grub-mkconfig will throw "WARNING: Failed to connect to lvmetad. Falling back to internal scanning."

(chroot) root@localhost:/#rc-update add lvm default

More steps to take:

SSD tricks

Warning
Using SSDs and also hybrid drives sacrifices some cryptographic security for speed-improvement and lower power consumption. See FAQs of cryptsetup for the details. Plan with drive's degradation and loss of space over time. With or without trim physical destruction of the drive is necessary. There are no guarantees that overwriting really changes bits in the drive's memory chips. This is not a problem of cryptsetup, LUKS or the kernel but caused by the firmware/ hardware/ vendor- and model-specific algorithms.

SSD trim allows an operating system to inform a solid-state drive (SSD) which blocks of data are no longer considered in use and can be wiped internally. Because low-level operation of SSDs differs significantly from hard drives, the typical way in which operating systems handle operations like deletes and formats resulted in unanticipated progressive performance degradation of write operations on SSDs. Trimming enables the SSD to more efficiently handle garbage collection, which would otherwise slow future write operations to the involved blocks. To enable SSD trim of encrypted root filesystem on LVM, edit the /etc/default/grub file if using genkernel:

FILE /etc/default/grub
GRUB_CMDLINE_LINUX="...root_trim=yes"

If using dracut to generate the intiramfs the use:

FILE /etc/default/grub
GRUB_CMDLINE_LINUX="...rd.luks.allow-discards"

If using systemd-based initramfs the use:

FILE /etc/default/grub
GRUB_CMDLINE_LINUX="...rd.luks.options=discard"

This will notify the kernel to enable trim on roots.

Edit the /etc/lvm/lvm.conf configuration file:

FILE /etc/lvm/lvm.conf
issue_discards = 1

This will notify LVM layer to enable SSD trim.

When using SSDs and UEFI-boot the boot sequence might be too fast. When entering the correct passphrase, the kernel will complain about missing modules or no root device. Try to add rootdelay=3 to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub, or directly append it in edit mode of the GRUB menu when booting.

Simple disk encryption without LVM

Encryption are works in such scenario:

OS makes I/O request to mapped filesystem on device /dev/mapper/myname. As internal layer in OS knows, that this mapped device are encrypted, it asks for Encryption OS layer to encrypted I/O data on "myname", and after that encrypted data goes to physical device, associated with "myname".

Creating partition

Start parted against the physical device (in this example, /dev/sdX is used). It is recommended to ask parted to use optimal partition alignment:

(chroot) root@localhost:/#parted -a optimal /dev/sdX

Now parted will be used to create the partitions. See Handbook:AMD64/Installation/Disks#Default:_Using_parted_to_partition_the_disk for information, how to create partition.

Just create partition with expected partition size, don't set partition type or format it. See next section for steps.

Create encryption layer for partition

After creating partition, encrypt this partition (where sdX is name of the device created at previous step):

(chroot) root@localhost:/#cryptsetup luksFormat /dev/sdX

Enter YES in uppercase. Enter password for encrypting disk. Now the encrypted disk is ready.

Create file system on encrypted layer

Open encrypted part of disk:

(chroot) root@localhost:/#cryptsetup luksOpen /dev/sdX myname

Where "myname" is name of the mapped device.

Create ext4 filesystem on the encrypted device:

(chroot) root@localhost:/#mkfs.ext4 /dev/mapper/myname

Final mount

Now encrypted device ready for final mount into system:

(chroot) root@localhost:/#mkdir -p /mnt/myname
(chroot) root@localhost:/#mount /dev/mapper/myname /mnt/myname

Manual work with encrypted partition

Open encrypted LUKS device

(chroot) root@localhost:/#cryptsetup luksOpen /dev/sdX myname

Mount encrypted LUKS device

And mount of this device into system:

root@localhost:/#mkdir -p /mnt/myname
root@localhost:/#mount /dev/mapper/myname /mnt/myname

Automatic mount of encrypted disk at boot

At boot, the service dmcrypt reads the configuration file /etc/conf.d/dmcrypt and gets a list of targets (devices) that should be mapped. After succesfully mapping and creating a mapped device at /dev/mapper/*, fstab will mount the device from /dev/mapper/* to some mount point.

First, create the directory that will contain the keys for encryption and decryption of the devices:

root@localhost:/#mkdir /etc/keyfiles
root@localhost:/#chmod 0400 /etc/keyfiles

Create 4KiB keyfile with name /etc/keyfiles/main:

root@localhost:/#dd if=/dev/urandom of=/etc/keyfiles/main bs=1024 count=4
root@localhost:/#chmod 0400 /etc/keyfiles/main

Add the /etc/keyfiles/main keyfile to the list of keys, that can decrypt the disk (technically: add the keyfile to the LUKS slot):

root@localhost:/#cryptsetup luksAddKey /dev/sdX /etc/keyfiles/main

Find the UUID of the encrypted disk with the blkid command. For example, blkid can return the following output:

root@localhost:/#blkid
/dev/sda1: UUID="91d7fd8f-fa64-42f3-8491-ba9464c0c064" TYPE="crypto_LUKS" PARTLABEL="media" PARTUUID="2e1aa997-7295-4e00-b03d-de0317c25342"
/dev/sda5: UUID="281c3e94-f195-47fc-b604-7b3d8c38a513" TYPE="crypto_LUKS" PARTLABEL="data" PARTUUID="7c41cc1a-b68b-4eae-97a9-9a28be10c6c3"
/dev/sdb1: UUID="4F20-B9DB" TYPE="vfat" PARTLABEL="grub" PARTUUID="70b1627b-57e7-4559-877a-355184f0ab9d"
/dev/sdb2: UUID="DB1D-89C5" TYPE="vfat" PARTLABEL="boot" PARTUUID="b2a61809-4c19-4685-8875-e7fdf645eec5"
/dev/sdb3: UUID="6a7a642a-3262-4f87-9540-bcd53969343b" TYPE="crypto_LUKS" PARTLABEL="lvm" PARTUUID="be8e6694-b39c-4d2f-9f42-7ca455fdd64f"
/dev/mapper/root: UUID="HL32bg-ZjrZ-RBo9-PcFM-DmaQ-QbrC-9HkNMk" TYPE="LVM2_member"
/dev/mapper/vg0-root: UUID="6bedbbd8-cea9-4734-9c49-8e985c61c120" TYPE="ext4"
/dev/mapper/vg0-var: UUID="61e4cc83-a1ee-4190-914b-4b62b49ac77f" TYPE="ext4"
/dev/mapper/vg0-home: UUID="5d6ff087-50ce-400f-91c4-e3378be23c00" TYPE="ext4"
/dev/mapper/data: UUID="4be7f323-3f7e-47c7-91a3-b37d04e951aa" TYPE="ext4"
/dev/mapper/media: UUID="943629b6-391d-441a-adf1-13fcb0471fd3" TYPE="ext4"

Note the filesystem labeled as crypto_LUKS type.

In this example, /dev/sda1 is encrypted with the /etc/keys/main key.

Configure the dmcrypt service. The dmcrypt service opens the LUKS encrypted device with /etc/keys/main key and maps it with some name. For example:

Edit file /etc/conf.d/dmcrypt:

FILE /etc/conf.d/dmcrypt
target='data'
source=UUID='91d7fd8f-fa64-42f3-8491-ba9464c0c064'
key='/etc/keyfiles/main'

In this example, dmcrypt will open the block device with UUID 91d7fd8f-fa64-42f3-8491-ba9464c0c064 with key /etc/keys/main and create a mapped mount point at /dev/mapper/data.

Check that dmcrypt works fine. Start the service manually:

root@localhost:/# /etc/init.d/dmcrypt start

If dmcrypt started without problems, there are no errors in /var/log/messages, and the mapped device /dev/mapper/data exists, then everything is fine and the dmcrypt service may be added to be started at the boot step.

Add dmcrypt to be started at boot:

root@localhost:/#rc-update add dmcrypt boot

Add to fstab where and how the mapped device should be mounted.

Find the UUID of the mapped devices. Execute the blkid command and find the UUID of mapped device /dev/mapper/data:

root@localhost:/#blkid
/dev/sda1: UUID="91d7fd8f-fa64-42f3-8491-ba9464c0c064" TYPE="crypto_LUKS" PARTLABEL="media" PARTUUID="2e1aa997-7295-4e00-b03d-de0317c25342"
/dev/sda5: UUID="281c3e94-f195-47fc-b604-7b3d8c38a513" TYPE="crypto_LUKS" PARTLABEL="data" PARTUUID="7c41cc1a-b68b-4eae-97a9-9a28be10c6c3"
/dev/sdb1: UUID="4F20-B9DB" TYPE="vfat" PARTLABEL="grub" PARTUUID="70b1627b-57e7-4559-877a-355184f0ab9d"
/dev/sdb2: UUID="DB1D-89C5" TYPE="vfat" PARTLABEL="boot" PARTUUID="b2a61809-4c19-4685-8875-e7fdf645eec5"
/dev/sdb3: UUID="6a7a642a-3262-4f87-9540-bcd53969343b" TYPE="crypto_LUKS" PARTLABEL="lvm" PARTUUID="be8e6694-b39c-4d2f-9f42-7ca455fdd64f"
/dev/mapper/root: UUID="HL32bg-ZjrZ-RBo9-PcFM-DmaQ-QbrC-9HkNMk" TYPE="LVM2_member"
/dev/mapper/vg0-root: UUID="6bedbbd8-cea9-4734-9c49-8e985c61c120" TYPE="ext4"
/dev/mapper/vg0-var: UUID="61e4cc83-a1ee-4190-914b-4b62b49ac77f" TYPE="ext4"
/dev/mapper/vg0-home: UUID="5d6ff087-50ce-400f-91c4-e3378be23c00" TYPE="ext4"
/dev/mapper/data: UUID="4be7f323-3f7e-47c7-91a3-b37d04e951aa" TYPE="ext4"
/dev/mapper/media: UUID="943629b6-391d-441a-adf1-13fcb0471fd3" TYPE="ext4"

In the example below, the UUID of the mapped device /dev/mappper/data is 4be7f323-3f7e-47c7-91a3-b37d04e951aa.

Important
Don't forget to start dmcrypt before this step.

Add those mapped devices to /etc/fstab. Edit /etc/fstab and add a row with the UUID, mount point, and filesystem type of the mapped device. For example:

FILE /etc/fstab
# encrypted devices
UUID=4be7f323-3f7e-47c7-91a3-b37d04e951aa       /mnt/data     ext4      defaults        0 2

Here UUID is the identifyer of the mapped device /dev/mapper/data, /mnt/data is the mount point, and ext4 is the filesystem type of the mapped device.

See encrypted device keys in SLOT

root@localhost:/#cryptsetup luksDump /dev/sda5