How to install and unlock your encrypted Debian root with a keyfile

Introduction

A common method for securing the root partition of a system is through encryption using a passphrase. While effective, this approach requires manual input every time the machine starts, which poses a challenge for headless machines that lack a keyboard or screen.

To address this, we can store the keyfile on a USB key, allowing the system to automatically access the encryption key during boot. Alternatively, the keyfile can be stored on the network, providing a convenient solution for multiple machines, but we will see that one day, maybe.

In this blog post we will install Debian 13 using debootstrap without setting up a passphrase. Although we could run the installer, which supports LUKS encryption with a passphrase, and add the keyfile later, where would be the fun?

Debian Installation

First, grab (a tea and) a live version of Debian, install it on a usb key (it's 2025, who still burns Linux distributions to CDs?), boot on it, and open a terminal.

We need to install a few packages:

sudo apt update
sudo apt install debootstrap arch-install-scripts

Let's assume you have the following setup:

  • sda is the disk where we are going to install the system (with its partitions being efi, boot and root, in that order);
  • sdb is the live usb key;
  • sdc is the usb key where we will install the keyfile.
NAME    SIZE RO TYPE    UUID
sda       1T  0 disk
├─sda1    1G  0 part    00a1
├─sda2    1G  0 part    00a2
└─sda3  958G  0 part    00a3
sdb     7.6G  0 disk
├─sdb1  3.5G  0 part
└─sdb2  3.2M  0 part
sdc       8G  0 disk
├─sdc1    8G  0 part    00c1

We will start with creating a 64B keyfile. You can adjust the command to your liking, e.g., if you want a larger key, or if you want it to contain text, an image, etc.:

mkdir /tmp/usbkey
sudo mount /dev/sdc1 /tmp/usbkey
dd if=/dev/urandom of=/tmp/usbkey/luks-keyfile bs=1 count=64

We can now create our new filesystem:

sudo mkfs.vfat -F32 /dev/sda1
sudo mkfs.ext4 /dev/sda2
sudo cryptsetup luksFormat /dev/sda3 --key-file /tmp/usbkey/luks-keyfile
sudo cryptsetup open /dev/sda3 cryptroot --key-file /tmp/usbkey/luks-keyfile
sudo mkfs.ext4 /dev/mapper/cryptroot
sudo umount /tmp/usbkey

And mount it:

sudo mount /dev/mapper/cryptroot /mnt
sudo mkdir /mnt/boot
sudo mount /dev/sda2 /mnt/boot
sudo mkdir /mnt/boot/efi
sudo mount /dev/sda1 /mnt/boot/efi

And install a basic Debian system:

sudo debootstrap stable /mnt http://deb.debian.org/debian

Let's also generate a few files (if the usb key with the keyfile is still plugged in, you might want to remove it from /mnt/etc/fstab):

sudo bash -c 'genfstab -U /mnt > /mnt/etc/fstab'

chroot to the new system

To enter our new system:

sudo arch-chroot /mnt

arch-chroot is provided by the arch-install-scripts package installed earlier. It is a quicker and more convenient way to mount the required file systems needed in the chroot and then chroot.

New installation setup

Install a few necessary tools:

apt update
apt install neovim grub-efi openssh-server cryptsetup-initramfs \
linux-image-amd64 linux-headers-amd64 initramfs-tools efibootmgr locales

Configure a few necessary things:

# root password
passwd

# hostname
echo my-encrypted-host > /etc/hostname
sed -i 's/debian/my-encrypted-host/' /etc/hosts

# setting the time & locales
dpkg-reconfigure tzdata
dpkg-reconfigure locales

# setting up the network
cat << EOF > /etc/systemd/network/<interface-name>.network
[Match]
Name=<interface-name>

[Network]
DHCP=yes
EOF

You might also want to allow password authentication for root via ssh, just at the beginning for debug purposes:

nvim /etc/ssh/sshd_config
...
PermitRootLogin yes
...

We can now enable the services:

systemctl enable sshd
systemctl enable systemd-networkd

Encrypted root configuration

Add a new entry in /etc/crypttab:

cryptroot	/dev/sda3	/dev/disk/by-uuid/00c1:/luks-keyfile	luks,discard,keyscript=/lib/cryptsetup/scripts/passdev

Also add a few modules in /etc/initramfs-tools/modules

ext4        # this is because our root partition uses ext4
nls_cp437
nls_ascii

Update Initramfs:

update-initramfs -u -k all

Install the bootloader:

grub-install --target=x86_64-efi --efi-directory=/boot/efi
update-grub

Et voilà! You can now exit the chroot, unmount the different disks, and reboot.

Note: please properly close the cryptroot mapping after unmounting /mnt:

sudo cryptsetup close /dev/mapper/cryptroot

Some references