Encrypt an existing Debian system with LUKS

This is how to encyrpt an existing Debian system using LUKS.

In this example the VM (virtual machine) has one virtual disk attached. You will need some megabytes free on your disk.

References

On Internet you can find other posts asking/showing how to encrypt a drive:

There was another tool that did the conversion on the fly, named luksipc. I am not sure you should use it.

Actual machine disk disposition

$ lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda       8:0    0    2G  0 disk
├─sda1    8:1    0  1.9G  0 part /
├─sda14   8:14   0    3M  0 part
└─sda15   8:15   0  124M  0 part /boot/efi
$ fdisk -l
Disk /dev/sda: 2 GiB, 2147483648 bytes, 4194304 sectors
Disk model: QEMU HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 56E4EDE3-4BA3-6942-9E58-D1EFDCB32B4A

Device      Start     End Sectors  Size Type
/dev/sda1  262144 4192255 3930112  1.9G Linux root (x86-64)
/dev/sda14   2048    8191    6144    3M BIOS boot
/dev/sda15   8192  262143  253952  124M EFI System

Partition table entries are not in disk order.
$ blkid
/dev/sda15: SEC_TYPE="msdos" UUID="E6F2-C0D9" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="cec893d8-f47d-4f0f-b0b7-c3f3a4fac1cf"
/dev/sda1: UUID="4594baf1-164a-4cb0-980f-105744df462c" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="54c133f2-e7f5-43a6-9540-cea1cbc4654c"
/dev/sda14: PARTUUID="3747106c-99e7-1748-8308-ee6ae31f457b"

Prepare the actual system

apt install cryptsetup cryptsetup-initramfs

Add GRUB_ENABLE_CRYPTODISK=y to /etc/default/grub

Ensure the keyboard layout is usable in /etc/default/keyboard

XKBMODEL="pc105"
XKBLAYOUT="fr"
XKBVARIANT="latin9"

Run update-initramfs -u

You can check that the cryptsetup is installed: lsinitramfs /boot/initrd.img-6.11.10+bpo-amd64 | grep crypt Using the filename from the update-initramfs command.

You may want to reboot and check that everything still works fine. Now shut down the machine.

Setup Debian live

  • Load https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/debian-live-12.9.0-amd64-standard.iso on a CD or USB stick.
  • Boot the VM/machine on the ISO.
  • Choose the "Live" option.
  • Install cryptsetup: sudo apt install cryptsetup -y

You will probably need to add the nameserver 1.1.1.1 line to the /etc/resolv.conf file. And add an IP manually

  • Check before with ip link.
  • sudo ip addr add 10.10.10.3/24 dev ens18.
  • sudo ip net add default via 10.10.10.1.
  • ping 1.1.1.1 should reply

At this point I installed openssh-server to work remotely: sudo apt install openssh-server -y And did allow root access and changed the root password. And restarted the service.

Start converting the drive

Run fdisk -l and find the drive path.

Now, you can paste the script from krzys-h's gist. Or use my version of this script:

#!/bin/bash

set -euo pipefail

# Uncomment to debug/inspect the commands
#set -x

# Encrypt an existing partition with LUKS2 on Debian 12

# DISCLAIMER: USE AT YOUR OWN RISK AND MAKE BACKUPS
# Made for my personal use and has almost NO error checking!!

# Based on instructions from:
# https://wiki.archlinux.org/index.php/dm-crypt/Device_encryption#Encrypt_an_existing_unencrypted_filesystem

DISK="${1:-}"

if [ -z "$DISK" ]; then
	echo "Usage: $0 /dev/sdXY"
	exit 1
fi

# Run a filesystem check
e2fsck -f "$DISK"

# Make the filesystem slightly smaller to make space for the LUKS header
BLOCK_SIZE=`dumpe2fs -h $DISK | grep "Block size" | cut -d ':' -f 2 | tr -d ' '`
BLOCK_COUNT=`dumpe2fs -h $DISK | grep "Block count" | cut -d ':' -f 2 | tr -d ' '`
SPACE_TO_FREE=$((1024 * 1024 * 32)) # 16MB should be enough, but add a safety margin
NEW_BLOCK_COUNT=$(($BLOCK_COUNT - $SPACE_TO_FREE / $BLOCK_SIZE))
resize2fs -p "$DISK" "$NEW_BLOCK_COUNT"

# Run the encryption process
# MAN: https://man7.org/linux/man-pages/man8/cryptsetup-reencrypt.8.html
cryptsetup reencrypt --encrypt --reduce-device-size 16M "$DISK"

# Resize the filesystem to fill up the remaining space (i.e. remove the safety margin from earlier)
cryptsetup open "$DISK" recrypt
resize2fs /dev/mapper/recrypt
cryptsetup close recrypt

# Don't forget to update /etc/crypttab and /etc/fstab if required!
#
# For example:
# /etc/crypttab
# crypt_root    UUID=xxx    none    luks
# /etc/fstab
# /dev/mapper/crypt_root    /        ext4    errors=remount-ro    0    1
#
# Remember to run "update-initramfs -u -k all" after updating the rootfs crypttab

Adjust the encryption key

As said on Debian's reddit and Unix StackExchange GRUB will not unlock if the keyslot is PBKDF: argon2id

You will need to run:

  • cryptsetup luksDump /dev/sda to check that is needs to be converted
  • cryptsetup luksConvertKey --pbkdf pbkdf2 /dev/sda to convert the key
  • cryptsetup luksDump /dev/sda to check that is worked
  • sudo cryptsetup --verbose open --test-passphrase /dev/sda to check the password is working

Note: always use --pbkdf pbkdf2 to change the password or do other key changes. Example to change the password: cryptsetup luksChangeKey --pbkdf pbkdf2 /dev/sda

Chroot into the system and adjust it

Thank you finnie.org for this part of the tutorial !

DEVICE_NAME="root_crypt"
cryptsetup open /dev/sda1 ${DEVICE_NAME}
mkdir /mnt/${DEVICE_NAME}
mount /dev/mapper/${DEVICE_NAME} /mnt/${DEVICE_NAME}
mount -t proc none /mnt/${DEVICE_NAME}/proc
mount -t sysfs none /mnt/${DEVICE_NAME}/sys
mount --bind /dev /mnt/${DEVICE_NAME}/dev

Enter the chroot: chroot /mnt/${DEVICE_NAME}

Once in the chroot

  • run fdisk -l and check if you have an EFI partition
    • If you have one, mount it: mount /dev/sda15 /boot/efi
  • run blkid -o value -s UUID /dev/sda1 and keep the value
  • edit /etc/crypttab and add the following line: root_crypt UUID=<blkid value here> none luks
    • Example: root_crypt UUID=24bfb42b-007d-4777-9889-46d3e016e60b none luks
  • edit /etc/fstab to change the root line
    • Example: PARTUUID=54c133f2-e7f5-43a6-9540-cea1cbc4654c / ext4 rw,discard,errors=remount-ro 0 1 Is now /dev/mapper/root_crypt / ext4 rw,discard,errors=remount-ro 0 1
  • Check that the /etc/mtab does not differ from reality: diff -u /etc/mtab /proc/mounts If it differs (the diff command returns a difference), run: cat /proc/mounts >/etc/mtab

Fix the boot process

  • Re-install grub grub-install /dev/sda (I am not sure this step is required)
  • Update initramfs: update-initramfs -k all -u
  • Run lsblk -o uuid,name
    • 24bfb42b-007d-4777-9889-46d3e016e60b ├─sda1
    • 4594baf1-164a-4cb0-980f-105744df462c │ └─root_crypt

In /etc/default/grub edit GRUB_CMDLINE_LINUX=

  • Add cryptdevice=UUID=<your_encrypted_crypt_device_uuid>:root_crypt root=UUID=<your_unencrypted_root_partition_uuid>
    • Example cryptdevice=UUID=24bfb42b-007d-4777-9889-46d3e016e60b:root_crypt root=UUID=4594baf1-164a-4cb0-980f-105744df462c
    • Example (should work) cryptdevice=UUID=24bfb42b-007d-4777-9889-46d3e016e60b:root_crypt root=/dev/mapper/root_crypt
  • Check that it boots on root= and has cryptdevice= by running cat /boot/grub/grub.cfg | grep -F "root="
  • Run update-grub
  • Check that it boots on root= and has cryptdevice= by running cat /boot/grub/grub.cfg | grep -F "root="

You can learn more about the boot parameters on the wiki page of Archlinux.

Exit the chroot: exit

Cleanup the chroot

umount /mnt/${DEVICE_NAME}/proc
umount /mnt/${DEVICE_NAME}/sys
umount /mnt/${DEVICE_NAME}/dev
umount /mnt/${DEVICE_NAME}/boot/efi
umount /mnt/${DEVICE_NAME}
cryptsetup close ${DEVICE_NAME}
rmdir -v /mnt/${DEVICE_NAME}

Finishing the job

Shutdown the live VM: poweroff And boot the machine to see if it works ?!

If the system hangs on random: crng init done then the unlock may be waiting for you on another TTY. Explained on RaspberryPi StackExchange.

Bonus commands: grow the LUKS partition and the ext4 partition to the full disk size

Thank you to foorschtbar (blog post on fotto.de) for the commands.

If you resize your VM disk, you may want to expand. This also works to do a live resizing of the root partition.

$ apt install -y parted
$ parted /dev/sda

GNU Parted 3.5
Using /dev/sda

(parted) print

Model: VMware Virtual disk (scsi)
Disk /dev/sda: 53.7GB
Partition Table: gpt

Number  Start   End     Size    File system  Name  Flags
14      1049kB  4194kB  3146kB                     bios_grub
15      4194kB  134MB   130MB   fat16              boot, esp
 1      134MB   2146MB  2012MB

(parted) resizepart

Partition number? 1
End?  [2146MB]? 100%

(parted) print

Model: VMware Virtual disk (scsi)
Disk /dev/sda: 53.7GB
Partition Table: gpt

Number  Start   End     Size    File system  Name  Flags
14      1049kB  4194kB  3146kB                     bios_grub
15      4194kB  134MB   130MB   fat16              boot, esp
 1      134MB   53.7GB  53.6GB

(parted) q

If you use LVM, use the blog post linked above.

# I assume the LUKS partition is open at the name root_crypt
cryptsetup resize root_crypt
# Resize the EXT-4 file system
resize2fs /dev/mapper/root_crypt
  • Reboot, all done.