Multiple Linux Distro Installs on a LUKS Encrypted Harddrive

Posted: December 18th, 2014 | Author: | Filed under: computing | Tags: , , , , | 13 Comments »


Install multiple linux distros on one machine that use the same encrypted container.


I’m setting up a new laptop with a 1 TB drive and want to be able to natively boot multiple distributions of linux, but also want everything in the drive except the necessary /boot partition to be encrypted. Each distro will have it’s own LVM volume within the encrypted container but I want all the LVMs to live within the same encrypted container so that data can be shared between volumes and I can grow/shrink/rearrange the logical volumes as needed.

Also.. just because.

The Challenges:

1) Boot partitions -- In a typical multiboot setup I would install Grub for the “primary” OS to the harddrive boot sector and then install the Grub for the secondary distros into their respective partition boot sectors. The primary Grub menu seen at boot would then be configured to chainload the secondary distros. Unfortunately this doesn’t work as simply with the LUKS setup above as Grub can’t access the secondary bootloaders if they are sitting in an encrypted LUKS container.

2) Dumb Installers -- In trying to keep things simple, the installer programs for many distros have been streamlined to the point they cannot support non-standard LUKS/LVM setups such as this.

The Process:

WARNING: FOLLOWING THESE STEPS IS GUARANTEED TO DESTROY EVERY BYTE OF EXISTING DATA ON YOUR HARD DRIVE. I’m serious -- the very first few steps will likely make any existing data unrecoverable by the best NSA jock using the latest secret-alien-area51 gear with unlimited funding. DO NOT PROCEED if you have not backed up every piece of needed data on the installation disk and have physically disconnected any other drives. This is NOT an exact step-by-step guide for beginners and assumes you are already familiar with linux installation and command-line administration.

Preparing the harddrive.

* This writeup assumes the installation harddrive is /dev/sda, adjust accordingly.

* Download and burn a linux installation disk with a Live option (e.g. latest Debian, Ubuntu or Mint). Alternative installers could be adapted as well if you know your stuff.

* Boot into the live environment, open a Terminal and “sudo su -” to obtain a root prompt.

* Create a temporary full disk partition to properly prepare the disk for encryption by first filling it with random data (this is where all existing data goes bye-bye). Use “fdisk /dev/sda” to delete any exiting partitions then create a full disk /dev/sda1 partition using the whole disk with default values. After saving the new table, if you get the following error:

WARNING: Re-reading the partition table failed with error 22: Invalid argument.
The kernel still uses the old table.
The new table will be used at the next reboot.
Syncing disks.

Then reboot before continuing or you will only overwrite whatever the old sda1 partition size was.

* The step of filling the new disk with random data is usually done with the agonizingly slow “dd if=/dev/urandom”. Thanks to these awesome guys we have a much quicker method available using a clever combo of /dev/zero and LUKS itself. (I now use this even for standard encrypted installs and can then skip the “wipe data” step provided by the installers.)

* Create a LUKS container using /dev/sda1:
# cryptsetup luksFormat /dev/sda1

This will overwrite data on /dev/sda1 irrevocably.
Are you sure? (Type uppercase yes): [YES]
Enter LUKS passphrase: [enter a random one-time-use password]
Verify passphrase: [re-enter password]

* Open the LUKS container:
# cryptsetup luksOpen /dev/sda1 sda1_crypt
[re-enter password]

* Fill the container data using /dev/zero. LUKS will encrypt the /dev/zero input as it writes. For me this is roughly 8x faster than the /dev/urandom method and the result is just as good (or better):
# dd if=/dev/zero of=/dev/mapper/sda1_crypt bs=1M

* Once complete, close the crypto device.
# cryptsetup luksClose sda1_crypt

* Overwrite the small LUKS header space for extra security.
# dd if=/dev/urandom of=/dev/sda1 bs=512 count=2056

Create the new permanent partitions and LUKS container.

* Use fdisk to create a new partition layout. The following layout provides boot partitions for 3 linux distros and the rest of the disk as the encrypted container. If you want more distos, format more boot partitions accordingly. It is possible to use the same /boot for more than one distro, but it will make all kinds of ugliness when you run update-grub. Unfortunately Grub2 is not nearly as refined as the old Grub in customizing these things yet. Using separate boot partitions keeps things easy and clean.

# fdisk /dev/sda
new primary partition 1 = /dev/sda1, 512Mb, type 83 Linux (/boot for primary distro)
new primary partition 2 = /dev/sda2, 256Mb, type 83 Linux (/boot for alternate distro)
new primary partition 3 = /dev/sda3, 256Mb, type 83 Linux (/boot for alternate distro)
new extended partition = /dev/sda4, (disk remainder) type 5 extended
new partition 5 = /dev/sda5, (disk remainder) type 83 Linux (this is the encrypted partition)

Also, if you want to install non-encrypted OS’s (e.g. Windows) then limit the size of the encrypted partition and create additional extended partitions for those OS’s. Note that most non-encrypted OS’s do not need separate boot partitions because they can be chainloaded from the Grub that will be installed in the primary harddrive boot sector. Also note that some versions of Windows may have trouble with booting from extended partitions so you would need to modify your layout accordingly. (Personally, I prefer never run to Windows outside of a Virtualbox).

* Now create the new crypto device. Note that the password you use here will be required each time you boot.

# cryptsetup luksFormat /dev/sda5

This will overwrite data on /dev/sda5 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase: [new password]
Verify passphrase: [re-enter password]

* Open the new crypto partition:
# cryptsetup luksOpen /dev/sda5 sda5_crypt

* Create a new LVM Physical Volume (PV) from the crypto partition:
# pvcreate /dev/mapper/sda5_crypt

* Create a new LVM Volume Group (VG) using the PV:
# vgcreate [vg-name] /dev/mapper/sda5_crypt

* Create new LVM Logical Volumes (LVs) for swap and root (/). The swap LV will be common for all the distros, but each distro will have it’s own root LV. It may be helpful to name the root LV based on distro (e.g. “kubuntu-root”). You can delete and create new LVs if you swap out distros later. You can also start small as it’s easy to grow the LV later using lvextend (and most filesystems with resize2fs) if you need more space.
# lvcreate -L[8G] -n [swap-lv-name] [vg-name]
# lvcreate -L[50G] -n [root1-lv-name] [vg-name]

* Check everything with “lvdisplay”. If it all looks good then leave the terminal window open and move to the GUI installer.

Installing the initial (primary) Linux distro

* Click on the Live CD’s gui installer icon (probably right on the desktop) and follow the instructions. When you get to the disk setup selections, select the Manual option. Use the screens to configure:
/dev/sda1 as format ext2, mount /boot
/dev/mapper/[vg-name]-[swap-lv-name] as swap area
/dev/mapper/[vg-name]-[root1-lv-name] as format ext4, mount /

All the other available partitions should be listed as “Do not use”.

* If/when you are presented with a Grub install choice, then install this grub instance to the harddrive boot sector “/dev/sda”.

* Complete the gui install, but once completed DO NOT REBOOT YET, instead click the “Continue Testing” option. LUKS must be configured before you reboot.

Enabling LUKS on the Linux distro

* Once the installer completes, you need to chroot from the Live CD environment into your newly installed distro so you can configure LUKS before rebooting.

* From the terminal window you were using previously (as root):
# mkdir /mnt/newroot
# mount /dev/mapper/[vg-name]-[root1-lv-name] /mnt/newroot
# mount -o bind /proc /mnt/newroot/proc
# mount -o bind /dev /mnt/newroot/dev
# mount -o bind /dev/pts /mnt/newroot/dev/pts
# mount -o bind /sys /mnt/newroot/sys
# cd /mnt/newroot
# chroot /mnt/newroot

You are now in the newly installed distro’s environment (the previous /mnt/newroot is now “/”).

* Mount the /boot partition for this distro (e.g. /dev/sda1 for the primary distro)
# mount /dev/sdaX /boot

* Get the UUID of the crypto partition you created previously with fdisk:
# blkid /dev/sda5

* Take the UUID given above (without the quotes) and create the file “/etc/crypttab” with the following single line. (This file will be the same for all linux distros within the LUKS container).
# nano /etc/crypttab

sda5_crypt UUID=your-blkid-goes-here none luks

* Check /etc/fstab to ensure everything looks okay. It should list mounts for swap, /boot and /.

* You may want to add the following line to /etc/default/grub to keep your grub menu clean. This will restrict Grub to only creating menu entries for items in this distro’s /boot partition instead of searching the entire disk and creating menu entries for everything it finds.

* Ensure that the “cryptsetup” and “cryptsetup-bin” packages are installed on the system (should be included on most modern distros) as well as initramfs-tools. For Debian based systems:
# dpkg -l | grep cryptsetup
# dpkg -l | grep initramfs

* Update the kernel boot images and grub menu:
# update-initramfs -u
# update-grub

# Take a look in /boot to ensure the initrd and vmlinuz images exist. Also take a peek at /boot/grub/grub.cfg to review your menu entries.

* Optional: If you want to save time and keep a tidy Grub menu then you can setup menu entries for your other distros now. They obviously won’t work until you install those distros, but it’ll save the step of having to boot back into the primary to update grub again after each install. To do this, add the “GRUB_DISABLE_OS_PROBER” entry mentioned above. Next, manually create the “chainload” entries for the other boot partitions by adding the following to the end of the 40_custom file.

# nano /etc/grub.d/40_custom

menuentry "Linux /dev/sda2 chainload" {
set root=(hd0,2)
chainload +1

menuentry "Linux /dev/sda3 chainload" {
set root=(hd0,3)
chainload +1

Once completed, run “update-grub” again and recheck your “/boot/grub/grub.cfg”. You should see these entries near the bottom.

* Time to take the plunge!
# reboot

* Make sure you eject the Live CD. Once the system reboots you should be presented with your Grub menu and shortly afterwards the boot process will pause and prompt for your LUKS password. Once entered you should boot into the normal user login prompt. Congrats!

Installing the additional Linux distros

* For installing the additional distros it’s easy to create the root LV for those while still logged into your primary distro. In a new terminal window:
$ sudo lvcreate -L[50G] -n [root2-lv-name] [vg-name]
$ sudo lvcreate -L[50G] -n [root3-lv-name] [vg-name]

There is no need to create a secondary swap LV. They’ll all use the same one.

* Reboot into the Live CD for the new distro. Once booted, open a terminal window and get to a root prompt like before.

* Now open the LUKS container:
# cryptsetup luksOpen /dev/sda5 sda5_crypt
[enter pass]

* Once open, activate the existing LVM LVs:
# lvscan

* If they didn’t automatically active then run:
# lvchange -a y

* If you didn’t already create the root LV for the new distro then do so now:
# lvcreate -L[50G] -n [root2-lv-name] [vg-name]

* Once again, leave the terminal window open and click on the Live CD’s gui installer and follow the instructions. When you get to the disk setup selections, select the Manual option. Use the screens to configure (use /dev/sda2 for the second distro /dev/sda3 for the third):
/dev/sda2 as format ext2, mount /boot
/dev/mapper/[vgname]-[swap-lv-name] as swap area
/dev/mapper/[vgname]-[root2-lv-name] as format ext4, mount /

DOUBLE CHECK that you are using one of the empty /boot partitions and root LV before proceeding or you will overwrite your existing install. Aside from swap, all the partitions for your other existing installs should be marked “Do not use”.

* Continue the install, when prompted for the grub installation choice, this time do not choose /dev/sda, but instead use the partition you defined as /boot (e.g. /dev/sda2). Grub may whine about being installed in a partition, but it works fine (at least for me so far.. knock on wood.)

* Complete the gui install, but again, once completed DO NOT REBOOT YET. Click the “Continue Testing” option.

* Follow the exact same steps as last time to chroot. Make sure you use the new root LV when mounting /mnt/newroot and the proper partition when mounting /boot.

* Use the same blkid process to create the /etc/crypttab file (it should be identical to the one you created last time).

* For these additional distros definitely disable the OS prober in /etc/default/grub. You do not need to add anything to 40_custom this time.

* Again, ensure that the “cryptsetup” and “cryptsetup-bin” packages are installed on this system (should be included on most modern distros) as well as initramfs-tools.

* And again, update the kernel boot images and grub menu for this distro:
# update-initramfs -u
# update-grub

* Reboot!
# reboot

At startup you should see the same Grub menu as before (from the grub installed in /dev/sda), but this time select the “Linux /dev/sda2 chainload” menu option. This will then chainload you to a second Grub menu for that distro. The beauty in this is each distro controls it’s own grub entries and only messes with it’s own initramfs images. You can shorten up the timeouts in the respective /etc/default/grub configs to keep the boot sequence quick. You may also edit the chainload entries in the primary distro’s /etc/grub.d/40_custom file to something more descriptive (maybe “My ub3r l33t h4x0r Kali Install” ;).


PS -- Comments and corrections are invited. I wrote this from memory, while consuming IPAs, a few weeks after the fact so I’m positive it’s full of holes.. hopefully not ones that leave you hanging, but Dragons There May Be.