Dual Ubuntu Installations with Whole Disk Encryption

My goal is I want to have a Xubuntu/Ubuntu dual boot, with a catch - I want the disk to be fully encrypted with the dm-crypt (native supplied) whole disk encryption. Now I know, out of the box the ubuntu installer is not going to make this simple for me, and maybe this is not doable, because I am not sure I can ultimately trick the tools into creating the two different initrd configurations for each root filesystem.

So questions:

  1. Has anyone done this before and is there a simple way I am missing to do this?

  2. Given (1) is a negative... a. Should I create separate base ecrypted volumes for each installation (xubuntu/ubuntu) or should I just create 1 encrypted volume and separate install partitions inside it? I am leaning toward the latter to make the process simpler. However I am not sure how the boot loader will handle this.

b. Once I get the first laid in, if I go with 1 encrypted volume, how do I decrypt it and install the second distro (and get the boot loader, initrd, etc updated properly)?

I've asked about the security aspects on Security Stack Exchange.


Here is the full account.

I have grouped the steps into phases between reboots:

  1. Preliminaries
  2. Back up your data
  3. Reboot to live-USB for main tasks a. pre-installation: make space on disk b. installation: do manual partitioning c. post-installation: supplement initramfs
  4. Reboot to primary Ubuntu to update grub
  5. Reboot to secondary Ubuntu to add keyfile
  6. Reboot to secondary Ubuntu for finishing touch
  7. Reminders for future installations
  8. About unencrypted /boot

0. Preliminaries

I have done this on a laptop that has BIOS (for UEFI details, see Ubuntu full disk encryption with encrypted /boot), and encrypted Ubuntu 15.10 already installed (but it could as well be 14.04 LTS). I have repeated the procedure to install Ubuntu 16.10 over earlier 16.04, and then to install 18.04 over earlier 16.10. However, I had to erase the contents of the logical volume that I used for root (/) for Bionic installation. Whenever I left it unerased, either Ubiquity or update-initramfs failed various ways.

Beginning with Cosmic, LUKS2 is the default, and grub only supports LUKS1. Therefore, you cannot begin with an installation of Cosmic or later and expect to be able to add another installation in the same container the way explained here. Instead, you have to do partitioning and create a LUKS1 container manually to begin with.

I will refer to partitions and LVM volumes by the names that were created by the standard Ubuntu installation on the hard disk /dev/sda:

$ lsblk -o NAME,TYPE,FSTYPE,MOUNTPOINT
NAME                    TYPE  FSTYPE      MOUNTPOINT
sda                     disk              
├─sda1                  part  ext2        /boot
├─sda2                  part              
└─sda5                  part  crypto_LUKS 
  └─sda5_crypt          crypt LVM2_member 
    ├─ubuntu--vg-root   lvm   ext4        /
    └─ubuntu--vg-swap_1 lvm   swap        [SWAP]

The LUKS container "sda5_crypt" takes up all space on the logical partition. Shrinking a LUKS container is far too difficult for me; I do not want to destroy the existing Ubuntu installation by attempting it. So instead, I decided to shrink the logical volume "root" to make room for new installations.

The only unencrypted space on the disk therefore is the 255M /boot partition. It would be possible to split this partition, but two equal halves would only hold two kernel versions each, and for me that is not enough. So instead, I decided to place the new /boot directory under the new / root (by not pointing it to any other location). This creates some extra complications, but also leaves room for multiple installations alongside the primary Ubuntu.

All commands in the following are to be executed with sudo rights, so I have skipped the sudo part from all command lines.

Also, I will be talking about "secondary Ubuntu", because I cannot know which Linux you wish to install. Replace "secondary Ubuntu" (and any details specific to Ubiquity) with your choice of flavor.

1. Back up your data

In addition to your normal backups, you might also want to create a separate copy of the essential settings (such as /etc/crypttab) into a location in which they are easily accessible. That will not be needed if all goes by the plan, but may help you keep your calm.

2. Reboot to live-USB for main tasks

2.a. pre-installation: make space on disk

Open the LUKS container and activate LVM.

cryptsetup luksOpen /dev/sda5 sda5_crypt
vgscan
vgchange -ay

Shrink the existing root volume.

e2fsck -f /dev/mapper/ubuntu--vg-root
#resize2fs -p /dev/mapper/ubuntu--vg-root 16G
lvreduce -L 16G --resizefs /dev/ubuntu-vg/root
  • The commented-out line is there just in case you don't trust "lvreduce --resizefs" to do the resize bit reliably. Run the "resize2fs" if it makes you feel better.

Add a new root volume. The size is up to you to choose; 16G is just an example.

lvcreate -L 16G -n root2 ubuntu-vg

Create a new swap only if you believe you can get hibernate to work with LUKS. Otherwise, let the two installations share the existing swap space.

lvcreate -L 4G -n swap2 ubuntu-vg

Creating a new data volume seems like an obvious thing to do, but it is not essential for the installation as described here.

lvcreate -l 100%FREE -n data ubuntu-vg

At this point, a newbie might want to reboot without the live-USB and log in to the primary Ubuntu just to see that it still works. If you do, remember to re-open the LUKS container again when you reboot back to the live-USB.

Moreover, be careful to use the right command to open the LUKS container. For example, if you click the icon you see in the Launcher side bar, the container will be opened by the wrong name, and that will cause update-initramfs later on to fail to do its job.

cryptsetup luksOpen /dev/sda5 sda5_crypt

2.b. installation: do manual partitioning

Launch the installer and choose "Something else" for installation type.

  • Point / to your new root volume (/dev/ubuntu-vg/root2).
  • Do not point /boot anywhere.
  • Point swap to your new swap volume if you created one, and otherwise to the old one.
  • Carefully check that no other partition or LVM volume takes part in the installation.
  • Place grub on a logical volume. It does not matter which volume, as the point is to ensure that gub-install fails. First time around, this is the safest option. Later, when you have done this many times, you will know exactly when to choose /dev/sda.

Proceed to the rest of the installation.

  • If the installer asks if mounts should be unmounted, you have done something not mentioned here. Unmount your extra mounts.

At end of installation, choose to continue testing.

  • When the installer reports that grub-install failed, choose to continue without grub.
  • If the popup window gets stuck, just minimize the installer window.

2.c. post-installation: supplement initramfs

Mount the both root volumes.

mkdir /mnt/newroot && mount /dev/mapper/ubuntu--vg-root2 /mnt/newroot
mkdir /mnt/oldroot && mount /dev/mapper/ubuntu--vg-root /mnt/oldroot

Copy the file /etc/crypttab form the old root volume to the new one.

cp -p /mnt/oldroot/etc/crypttab /mnt/newroot/etc/
cat /mnt/newroot/etc/crypttab

If the file you copied already refers to a keyfile, copy also the keyfile and the script that you need to load the key to initrd.img.

cp -p /mnt/oldroot/crypto_keyfile.bin /mnt/newroot/
cp -p /mnt/oldroot/etc/initramfs-tools/hooks/crypto_keyfile /mnt/newroot/etc/initramfs-tools/hooks/
  • On the first time around, the key does not exist yet, and it is better to create it in a later step, because trouble-shooting is easier when changes are not all made at once.

The crucial final step is to load the changes to initrd.img in chroot jail.

for DEV in dev dev/pts sys proc; do mount --bind /$DEV /mnt/newroot/$DEV; done

chroot /mnt/newroot update-initramfs -u

# Note reverse order.
for DEV in proc sys dev/pts dev; do umount /mnt/newroot/$DEV; done
  • If you get an error message saying "cryptsetup: WARNING: invalid line in /etc/crypttab", you did not open the LUKS container by the right name.

Tidy up (not 100% necessary, especially if you did not choose persistence when you created your live-USB).

umount /mnt/oldroot && rmdir /mnt/oldroot
umount /mnt/newroot && rmdir /mnt/newroot

You could also try to tidy up by closing the LUKS container, but if you had to minimize the installer window, you will get an error message saying "Device or resource busy". Don't worry, it will be closed in shutdown anyway.

cryptsetup luksClose sda5_crypt
  • The hardest part is now over.

3. Reboot to primary Ubuntu to update grub

Edit file /etc/default/grub to enable the encrypted /boot to include:

GRUB_ENABLE_CRYPTODISK=y
GRUB_CMDLINE_LINUX="cryptdevice=/dev/sda5:sda5_crypt"
  • If you set the value of GRUB_ENABLE_CRYPTODISK to "true" or "1" or anything else, update-grub will complain the value should be "1", but it really has to be "y". This is a known bug.
  • As usual, be careful not to add a newline to the end of the file.

Next, update grub -- mainly to add the newly installed Ubuntu to the menu, but also for the modified settings.

update-grub

4. Reboot to secondary Ubuntu to add keyfile

When you choose the secondary Ubuntu from grub menu, you will be asked for a password to open the LUKS container. And then you are asked for the same password again. Once you have logged in, we need to fix the problem of having to type in the password twice. We do it by adding a keyfile to the LUKS container.

First, we want to know how many keys the LUKS container already has. A LUKS container can have up to eight keys (numbered 0..7), so we only want to create the keys that we really need.

cryptsetup luksDump /dev/sda5
  • In Wily Werewolf, the container already has three keys. No idea why.

Next, we create the new keyfile.

dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin
chmod a=,u+r /crypto_keyfile.bin

Then we add the new key to the container. The command will as for an existing password, so type in the one you know.

cryptsetup luksAddKey /dev/sda5 /crypto_keyfile.bin

We still need a script that update-initramfs runs to load the key to initrd.img. Place the file in /etc/initramfs-tools/hooks/, and set its protection.

chmod +x /etc/initramfs-tools/hooks/crypto_keyfile

The script only needs to have one line in it:

cp /crypto_keyfile.bin "${DESTDIR}"
  • The name of the script, as well as the name of the keyfile, is up to you to decide.

We also have to add a reference to the key to /etc/crypttab. Before the modification, it looks like this:

sda5_crypt UUID=sda5-uuid-here none luks,discard

After the modification, it should look like this:

sda5_crypt UUID=sda5-uuid-here /crypto_keyfile.bin luks,discard,keyscript=/bin/cat

Now we are finally ready to update the initramfs:

update-initramfs -u

5. Reboot to secondary Ubuntu for finishing touch

This time, when you choose the secondary Ubuntu from grub menu, you will need to type in the LUKS password only once.

Copy the keyfile to the old root volume for backup.

mkdir /mnt/oldroot
mount /dev/mapper/ububtu--vg-root /mnt/oldroot
cp /crypto_file /mnt/oldroot/

Copy also the grub settings across for backup (from the old root volume to the new). Since the grub menu is shared by both installations, its settings are the same to the both, and the menu can be installed through either installation. So even if you prefer to keep the primary Ubuntu at top of the menu for now, you may need a backup copy of the settings later on.

cp /mnt/oldroot/etc/default/grub /etc/default/
umount /mnt/oldroot
rmdir /mnt/oldroot

You may also want to modify the mount options of the logical volumes (root volumes mainly), so that the two installations do not expose each other's private parts in the GUIs. I could give you a pattern for /etc/fstab, but fortunately Disks makes such a decent job that I don't need to.

Finally, you can begin the normal deployment of the secondary Ubuntu, and also deploy the new data volume in both installations.

6. Reminders for future installations

  • When overwriting either of the Ubuntu installations, you have to always repeat the same post-install steps, except the creation of a new keyfile for LUKS.
  • The need for the keyfile may disappear in any future release. Actually, I have found no proper documentation for the cryptsetup part of the installation, so I'm afraid anything about it could change. Beware!

7. About unencrypted /boot

If you choose to split the unencrypted primary partition to make room for the new /boot, you can drop out some of the steps I presented:

  • You do not need a keyfile, so you also do not need the script to load the key into initrd.img, and you do not need to add a reference to the keyfile into /etc/crypttab. Even so, you still need to add the /etc/crypttab file and run update-initramfs in chroot jail in post-installation phase.
  • If the new /boot is not encrypted, you also do not need GRUB_ENABLE_CRYPTODISK in your grub ssettings, and you do not need to set startup parameters to GRUB_CMDLINE_LINUX. Even so, you still need to run update-grub to add the secondary installation to grub menu.