Booting two Devuan GNU/Linux installed on encrypted partitions on a single disk

Followup of previous article (Single passphrase to boot Devuan GNU/Linux with multiple encrypted partitions), I found out that if you have two clone system, both on encrypted partitions, on the same hard disk, grub/os-prober as of today fails to automatically configure boot for the clone.

It the concept of having such clone system odd? Not really if you think of laptop that you use for two completely unrelated activities (work and out of the work?), that you do not want to mix at all.

I spent quite a time trying to understand why the clone system was ignored by os-prober and all, even though the partition it was on was mounted.

In the end, I decided it was easier to actually clone the config built for the running system, adjusting the UUID of partitions than to look further.

Here is my /etc/grub.d/11_linux_cryptoclone wrapper for /etc/grub.d/10_linux:

#! /bin/bash
set -e

# require GRUB_LINUX_CLONE_MAPPER_NAME to be set
# for instance to XY if the relevant fs is /dev/mapper/XY
# along with relevant grub parameters
#GRUB_ENABLE_CRYPTODISK=y
#GRUB_PRELOAD_MODULES="luks cryptodisk lvm"
#GRUB_LINUX_CLONE_MAPPER_NAME=XY

. /etc/default/grub
[ x"$GRUB_LINUX_CLONE_MAPPER_NAME" == x ] && exit

# setup
CLONE=$GRUB_LINUX_CLONE_MAPPER_NAME # only necessary to edit
CLONEUUID=`blkid /dev/mapper/$CLONE -o value -s UUID`
CLONENAME="Devuan GNU/Linux (on $CLONE)"
CLONECRYPTOUUID=`grep $CLONE /etc/crypttab | awk '{print $2}' | cut -f 2 -d =`
CLONECRYPTOUUIDGRF=`echo $CLONECRYPTOUUID | tr -d -`

ORIG=`df / --output=source | tail -1 | tr -d /dev/mapper`
ORIGUUID=`blkid /dev/mapper/$ORIG -o value -s UUID`
ORIGNAME="Devuan GNU/Linux"
ORIGCRYPTOUUID=`grep $ORIG /etc/crypttab | awk '{print $2}' | cut -f 2 -d =`
ORIGCRYPTOUUIDGRF=`echo $ORIGCRYPTOUUID | tr -d -`

# produce arranged conffile
>&2 echo "$ORIG -> $CLONE:"
`dirname "$0"`/10_linux | sed s/$ORIGCRYPTOUUID/$CLONECRYPTOUUID/ig | sed s/$ORIGCRYPTOUUIDGRF/$CLONECRYPTOUUIDGRF/ig | sed s/$ORIGUUID/$CLONEUUID/ig | sed s@"$ORIGNAME"@"$CLONENAME"@ig
>&2 echo " $ORIGCRYPTOUUID -> $CLONECRYPTOUUID"
>&2 echo " $ORIGUUID -> $CLONEUUID"

# make sure there is proper kernel and initrd installed
MCLONE=0
CLONEDIR=`grep /dev/mapper/$CLONE /etc/mtab | awk '{print $2}'`
if [ "x$CLONEDIR" == "x" ]; then
 MCLONE=1
 mount /dev/mapper/$CLONE
 CLONEDIR=`grep /dev/mapper/$CLONE /etc/mtab | awk '{print $2}'`
fi
for file in /boot/config-* /boot/init* /boot/vmlinuz-* /boot/System.map-*; do
 [ ! -e "$CLONEDIR/$file" ] && >&2 echo " $CLONE $file missing!"
done
>&2 echo " (remember $CLONE needs properly built initramfs)" 
if [ $MCLONE == 1 ]; then umount /dev/mapper/$CLONE ; fi

# EOF

As said it requires you to add GRUB_LINUX_CLONE_MAPPER_NAME=XY in /etc/default/grub, XY  being the /dev/mapper/XY of the clone system.

It expect the clone system to be similarly set up: it needs to have proper initramfs for the same kernel.

It also expect this clone system to be accessible and set in /etc/crypttab et /etc/fstab, since it needs to be able to find clone UUIDs which should not come as a surprise because if it would have to be if os-prober was to find it anyway.

Once done, you can simply run

update-grub

Single passphrase to boot Devuan GNU/Linux with multiple encrypted partitions

These days, considering the amount of data are stored on an average computer and how easy is it to get access to it once you get physical access, running such computer without any form of encryption seem unsound. Especially since it is reasonably easy to set up a en encrypted system and does not seems to imply much overhead.

When you have an old setup you are fine with, using numerous partitions or systems, it can be inconvenient, though. For instance  if you have to type a long specific passphrase 5 times when booting your computer.

There are a few things I found useful to make my life easier. Obviously, any shortcut security wise means less security. It is help to you to decide whether the risk is worth it or not depending on what kind of data you carry, what kind of attackers you expect, etc. This is part 1.

Single passphrase to boot GNU/Linux with multiple encrypted partitions

One obviously approach to type a single passphrase to boot a system is to have the boot loader files on a regular partition and the rest on a single encrypted partition. In GNU/Linux case, you would have /boot on a specific non-encrypted partition. Fact is anyone with access to your computer can easily replace your kernel or initramfs with a malicious one and you would not notice.

So I think non-encrypted /boot is as much of the table as would be a non-encrypted swap partition.

So for the boot manager grub to load, /boot need to be readable: the passphrase will be required here. The idea is that from this moment on, a keyfile will be used instead of passphrase to load any other partition.

I guess there is not much point to describe in detail the crypt setup itself (I followed the many guides out there). For each partition you want:

# 1. you create the partition with parted/fdisk

# 2. you format it as encrypted
cryptsetup luksFormat /dev/sdX1

# 2b. you record it in crypttab
# <target name> <source device> <key file> <options>
echo "Name1 UUID=`blkid -s UUID -o value /dev/sdX1` /boot/k/ka luks,tries=3" >> /etc/crypttab

# 3. you open the encrypt-formatted partition
cryptsetup luksOpen /dev/sdX1 Name1

# 4. you format the resulting /dev/mapper... to a regular filesystem
mkfs.ext4 /dev/mapper/Name1 -L Name1

# 4b. you record it in fstab (adjusting the mount point!)
# <file system> <mount point> <type> <options> <dump> <pass> 
echo "/dev/mapper/Name1 / ext4 errors=remount-ro 0 1" >> /etc/fstab

# you are set, you can mount the partition, 
#  and install the system/copy the system there

The swap  require specific treatment. Provided you know one with partition is the current  unencrypted swap is (here sdX?), this is enough:

# update crypttab
echo "SW `find -L /dev/disk -samefile /dev/sdX? | grep by-id | tail -1` /dev/urandom swap" >> /etc/crypttab

# update fstab
echo "/dev/mapper/SW  none   swap sw 0 0" >> /etc/fstab

Noticed the /boot/k/ka? That’s the unlocking key. You can use whatever other filename, just be consistent.

# generate some
dd if=/dev/urandom of=/boot/k/ka bs=1024 count=4
chmod 400 /boot/k/ka

# and obviously, add it to any luks formatted partition:
for part in `blkid | grep crypto_LUKS | awk {'print $1 '} | tr -d :$`; do cryptsetup -v luksAddKey $part /boot/k/ka; done

Then, you need a proper initramfs:

# dracut works almost out of the box
apt install dracut

# set up a few things
echo 'omit_dracutmodules+="systemd systemd-initrd dracut-system"' > /etc/dracut.conf.d/00-systemd.conf
echo 'add_dracutmodules+="crypt lvm"
install_items+="/sbin/e2fsck /sbin/cryptsetup /boot/k/ka"' > /etc/dracut.conf.d/99-luks.conf

# (re)build ramfs
dracut --force

# make sure there are no old initrd leftovers, that would confuse grub
rm /boot/initrd* -f

 

Then, you need to edit grub (version 2!) config:

# first obtain the UUID of crypted partition (not the /dev/mapper/... one) 
# that hold the /boot partition. 
# (it was Name1 earlier but obviously it depends to the real name you gave)
grep Name1 /etc/crypttab

# now edit /etc/default, with XXXXXXXXXXXX being the UUID value
# you just found.
GRUB_CMDLINE_LINUX="rd.luks.key=/boot/k/ka:UUID=XXXXXXXXXXXX"
GRUB_ENABLE_CRYPTODISK=y
GRUB_PRELOAD_MODULES="luks cryptodisk lvm"

# and now update-grub (install grub if not done yet)
update-grub

It took me a while to find the proper rd.luks.key value, no docs I read were clear about it. Many give the impression that putting rd.luks.key=/keyfile or rd.luks.key=/keyfile:/ would be enough since the key is actually on the same partition as grub.cfg. But no.

That is all. Rebooting now, you should be asked for the passphrase before getting the grub menu. And then boot process should be uninterrupted.