Full-disk encryption is essentially a requirement for a mobile OS. While there are a few choices for full block device encryption on Linux (such as Truecrypt), at this time the clear choice is Linux Unified Key Setup. LUKS integrates with dm-crypt as the encryption backend, producing a device mapper entry for the decrypted block device that can be used like any other.

In part one of our Fedora migration odyssey, we cloned the installation to a laptop. Now in part two, we will shift things around to move to a LUKS-encrypted root. What follows assumes that we are using the new laptop for all operations, and that our cloned system drive is the only one in place (sda). While everything can be done in rescue mode, some operations require it and will be noted.

The Plan

We have the following partition and volume layout:

/dev/sda (150GB)
     sda1: ext3 /boot (300MB)
     sda2: ext3 / (38GB)
     sda3: lvm Volume00 (112GB)
          Volume00-home: ext3 /home (70GB)
          Volume00-swap: swap (2GB)
          unallocated: (40GB)

The official documentation indicates that there is no way to encrypt-in-place and thereby preserve data (although tools such as luksipc suggest otherwise). Regardless, we will use that unallocated space, perfectly sized, to create a new root filesystem on top of a crypto-volume using LVM/LUKS, and then copy data. A move provides a secondary benefit here: it will fold root back into LVM, its excursion to a bare partition being only ever a mere workaround.

Last but not least, a copy leaves our existing root undisturbed as a fallback in the event of problems.

Create a New Crypto Volume

First we create an LVM volume using all of that free space:

vgs
  VG #PV #LV #SN Attr VSize VFree
  Volume00 1 2 0 wz--n- 111.76g 40.76g

lvcreate -n root -l+100%FREE Volume00

vgs
  VG #PV #LV #SN Attr VSize VFree
  Volume00 1 3 0 wz--n- 111.76g 0

lvs
  LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
  home Volume00 -wn-ao---- 69.00g
  root Volume00 -wi-ao---- 40.76g
  swap Volume00 -wi-ao---- 2.00

Rather than put a filesystem directly on the new volume, we will set up for encryption. For the best encryption results, it is recommended to write random data to the device:

dd if=/dev/urandom of=/dev/mapper/Volume00-root
dd: writing to ‘/dev/mapper/Volume00-root’: No space left on device
85483521+0 records in
85483520+0 records out
43767562240 bytes (44 GB) copied, 11330.7 s, 3.9 MB/s

NOTE: This will take some time.

Encrypt the volume:

cryptsetup --verbose --verify-passphrase luksFormat /dev/mapper/Volume00-root

WARNING!
========
This will overwrite data on /dev/mapper/Volume00-root irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
Command successful.

NOTE: Remember that passphrase. If lost, data will be irrecoverable.

Review the encryption summary for the device, noting the UUID:

cryptsetup luksDump /dev/mapper/Volume00-root
...
cryptsetup luksDump /dev/mapper/Volume00-root | grep UUID
UUID:          	cc7e78ee-87a9-4ad0-9c82-31de01389b34

Open the crypto-volume. The last argument specifies the device-mapper name by which this volume will be opened:

cryptsetup luksOpen /dev/mapper/Volume00-root luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34

NOTE: Naming by UUID is how Fedora sets these volumes up when creating them at install time, practice we will adhere to later when setting up the new root. For consistency’s sake, we do so now, but we could just as easily call it “luks-root” or some such for convenience at this stage.

Create a filesystem:

mkfs -t ext3 /dev/mapper/luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34

Copy Data

At this point, we should boot to rescue mode if not already. Because we are copying the existing root volume, we cannot afford to have it mounted at / where it could change. A read-only remount could suffice, but is likely to cause issues on a live system. Additionally, though we tell rsync not to cross filesystem boundaries anyway (-x), it is best reduce to zero the risk of copying special fileystems or other partitions that may be mounted beneath root.

We mount the source and destination, and rsync the contents:

mkdir /oldroot
mount /dev/sda2 /oldroot
mkdir /newroot
vgchange -ay
cryptsetup luksOpen /dev/mapper/Volume00-root luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34
mount /dev/mapper/luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34 /newroot
rsync -avx /oldroot/ /newroot

Requirements for Switching to a New Root

There are three elements necessary for successful switch to a new root, be it partition, lvm, crypto-volume, floppy, or who knows what else. In the order they are encountered in the boot process:

  1. GRUB: The bootloader needs to be configured properly to load the appropriate kernel executable with necessary arguments indicating where to find the new root.
  2. Initial RAM Disk: The initramfs image (or older initrd) needs to be built with enough utility so that the kernel can make use of it to find the real root filesystem. It may or may not already be capable, depending on suitable kernel arguments specified in grub.
  3. fstab: Configuration in /etc/fstab must be set to mount the new root at / with suitable mount options.

It is certainly possible to attempt to fight through each stage of the boot process, making run-time manual changes to grub and the dracut environments in order to find one’s way into the new root, confirming it works before making configuration changes. This entails having a decent amount of intelligence about how various rd.* kernel arguments will relate to one’s system. This is definitely a worthy endeavor and is certainly the approach to take when troubleshooting. But in the end, we will proceed directly to making the system changes for the new root, first making backups of the involved files, thereby allowing us to use the original root as a fallback without too much trouble.

Configure the System for a New Root

The modern tools necessary to build the bootloader config (grub2-mkconfig) and initramfs image (dracut), do a wonderful job of auto-configuring themselves. This is both a blessing and a curse, as we need to carefully establish an environment from which they can reliably draw their bits. This means running them from within the new root for best results, necessitating a boot to rescue mode.

Boot to rescue mode and make sure not to select “find drives automatically.” Instead, we will assemble what we need manually. The following is the surest path I have found to setup an environment for building clean grub configuration and initramfs image:

mkdir /mnt/sysimage
vgchange -ay
cryptsetup luksOpen /dev/mapper/Volume00-root luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34
Enter passphrase for /dev/mapper/Volume00-root:
mount /dev/mapper/luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34 /mnt/sysimage
mount /dev/sda1 /mnt/sysimage/boot
mount --bind /proc /mnt/sysimage/proc
mount --bind /dev /mnt/sysimage/dev
mount --bind /sys /mnt/sysimage/sys
chroot /mnt/sysimage

NOTE: If this was not a crypto-volume, the procedure still stands, mounting the LVM volume directly.

We have assembled the system from new root up, and are now prepared to re-configure and rebuild.

Make backups of the initramfs image and grub configuration:

cd /boot
cp -a initramfs-3.12.8-300.fc20.i686.img initramfs-3.12.8-300.fc20.i686.img.20140608
cd /boot/grub2
cp -a grub.cfg grub.cfg.20140608

NOTE: Grub configuration problems are relatively easy to work around at boot time, especially with a backup of the initramfs. Initramfs-specific problems less so. The initramfs may also be difficult to restore to original state depending on the nature of the problem. In other words, make sure to back up the initramfs.

Build the new initramfs image:

dracut -f /boot/initramfs-3.12.8-300.fc20.i686.img 3.12.8-300.fc20.i686

Alter grub configuration at /etc/default/grub, adding an argument informing our kernel that it should open our new crypto-volume:

GRUB_CMDLINE_LINUX="quiet rhgb rd.luks.uuid=cc7e78ee-87a9-4ad0-9c82-31de01389b34"

NOTE: Multiple crypto-volumes can be listed here, each resulting in a password prompt at boot time.

Build the new grub config:

grub2-mkconfig -o /boot/grub2/grub.cfg

NOTE: We should see entries for our old root as well, from the os-prober stage of grub2-mkconfig, though they may not work without some urging at the dracut prompt during boot.

This should produce a grub.cfg entry containing a kernel line reflecting our changes:

linux   /vmlinuz-3.12.8-300.fc20.i686 root=/dev/mapper/luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34 ro quiet rd.luks.uuid=cc7e78ee-87a9-4ad0-9c82-31de01389b34

Finally, alter fstab to mount our new root volume:

/dev/mapper/luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34	/	ext3	defaults,user_xattr 1 1

NOTE: Over the years, distros have moved from mounting by device to mounting by label or UUID, or at least device-mapper name, since devices can change. We could do this here as well, for example mounting by the UUID of the filesystem within our crypto volume (UUID=551227f2-7ea4-4c5d-8bed-a5bff1d7354f). Fedora seems to mount crypto volumes by device-mapper name and so shall we.

Crypttab? It is possible to create an /etc/crypttab file containing an entry like this:

luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34 /dev/mapper/Volume00-root none

A stock Fedora install on a crypto-root does not create this file, but its existence may (or may not) eliminate the need to specify rd.luks.uuid on the kernel command-line, among other things. I did not create this file on my system. Your mileage may vary.

Boot the New Root

At this point, we can boot into our new crypto-root. Following the above procedure should drastically reduce the chances of problems, but if they do occur, we are well-prepared to troubleshoot and recover with the knowledge we have gained and the backups we have made (see Working GRUB and Working Dracut).

We are left with this on the system drive:

/dev/sda (150GB)
     sda1: ext3 /boot (300MB)
     sda2: ext3 / (38GB)
     sda3: lvm Volume00 (112GB)
          Volume00-home: ext3 /home (70GB)
          Volume00-swap: swap (2GB)
          Volume00-root: LUKS (40GB)
               luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34 ext3 (40GB)

Ultimately, a successful move to a new crypto-root. In part three, we will concern ourselves with other volumes, namely home.