Since my old notebook computer recently gave up on me, I had to install a new one from scratch. I finally decided to give Ubuntu a go, after I had been using Debian (testing) for almost a decade. I must say that I’m really impressed with Ubuntu’s lean installation process, which handles diverse aspects like live-preview, hardware-detection, pre-existing operating systems, partitioning, etc. in a very convenient manner.
However Ubuntu also seems to come with several annoyances and limitations. I plan to figure out solutions for most of these in the following days, but one thing struck me right in the beginning: disk encryption. Sure, Ubuntu comes with easy support for encrypted home directories, but for reasons listed below that’s not exactly what I need.
According to an article by the EFF, the latest (12.10) Ubuntu installer already comes with built-in support for full-disk-encryption. Apparently, this feature only works when you’re installing Ubuntu alone, on an otherwise empty physical disk. Sadly, I wasn’t offered this option when trying to install alongside an existing OS. (Or maybe I just overlooked the feature, which would make most of the information provided here rather less essential. However, this article is still useful as a starting point for more exotic installations and as a reference for trouble-shooting.)
Update: By now I have successfully tested Ubuntu’s built-in support for full-disk-encryption on a different computer. When installing on an empty disc (or completely replacing an existing OS installation) it works as expected. The outcome – in terms of partition, luks, and lvm setup – is very similar to the one presented here. Hence I can fully recommend it, if applicable to one’s pre-existing setup!
Preconditions and encryption requirements
I partially use my computer for development work, and I like to toy around with system-wide settings. That’s why:
- Encryption should cover all the files on my Ubuntu disk partition. In particular files in etc (might contain passwords) and var (e.g. MySQL DBs) must also be covered. This helps prevent data leakage.
- Encryption must cover Linux swap areas. These might contain secret data of running programs, like passwords and keys.
- Additional un-encrypted disks and partitions should still be possible. In particular other operating systems should still run in a multi-boot fashion. These may be encrypted by their own means, or not at all.
- Encryption should integrate neatly with Ubuntu. It must work with latest Ubuntu 12.10 (Qunatal) and should be ready for future versions.
- Encryption does not need to isolate data of multiple users against each other. I’m the only one using the machine most of the time. And the only one with root access.
I used to have a setup that addressed all these requirements on my old Debian box. As far as I remember the Debian installer had offered a rather reasonable partitioning scheme with luks encryption and lvm volumes – though some manual interaction may have been needed. It is this kind of setup I was aiming to reproduce with Ubuntu.
Setting up full-disk-encryption while installing Ubuntu
So I first checked the encryption capabilities of the Ubuntu installer. The presets it offers are very convenient, but as mentioned above, support for full-disk encryption seems somewhat limited. Even the manual partitioning tool of the installer, only seems to provide very basic support for encryption. E.g. it offers dm_crypt, but does not have any (good) luks support.
So I had to abort the install, which got me back to the Ubuntu live-session. Being a GUI junkie, I first did some basic partitioning work (shrinking and moving old windows partitions) with gparted. Then I used the same to create the following 2 new partitions:
- /dev/sda5 – ext4, 1GB:
intended for an unencrypted /boot partition
- /dev/sda6 – unallocated, a gazillion GB (I wish):
intended for my encrypted Ubuntu installation and data
Next I used the CLI-tool cryptsetup to initialize an encrypted luks-container:
sudo cryptsetup luksFormat /dev/sda6
sudo luksOpen /dev/sda6 crypt1
The first command generates a new encryption-container on sda6 and asks for a passphrase to protect it. (Should be chosen wisely! However, luks also gives you the possibility to add or remove passphrases later.) The second command opens the new encryption-container (asking for the passphrase) and makes its contents available under /dev/mapper/crypt1.
Now, lvm comes into play:
sudo pvcreate /dev/mapper/crypt1
sudo vgcreate system-volumes /dev/mapper/crypt1
sudo lvcreate --name swap --size 3G system-volumes
sudo lvcreate --name root --extents 100%FREE system-volumes
This creates a new physical volume (pv) and a new volume group (vg) called system-volumes inside the encryption container. It then creates two logical volumes in this volume-group:
- /dev/system-volumes/swap – 3GB:
intended for a linux swap
- /dev/system-volumes/root – the rest of the free space (extents):
intended for the root file-system
That’s basically it. Without exiting the Ubuntu live-session, I started the installer tool again, and did the rest of the work with its GUI. GParted didn’t seem to recognize the new logical volume devices, but the partitioning-tool of the installer did. So I formatted the new volumes, and mapped everything to the following mount-points:
- /dev/sda5 → /boot (ext4)
- /dev/system-volumes/root → / (ext4)
- /dev/system-volumes/swap (linux-swap)
I also chose to install Grub into the MBR of /dev/sda and continued installing Ubuntu.
The installation finished flawlessly – but the first boot into the new system did not. It did not ask to decrypt the encryption-container on sda6 and therefore could not find any root file-system to mount. Instead, the boot process fell back to a BusyBox shell, and I had to decrypt it manually. As above, the following command does the trick:
luksOpen /dev/sda6 crypt1
The exit command terminates the shell and resumes the boot process, which will now find the root file-system and continue to boot. In my case, this lead me all the way to a working Ubuntu desktop.
Since I did not want to do this manually on each boot, a few more steps were necessary. After my Ubuntu system fully booted, I created the following entry in /etc/crypttab:
# <target> <source device> <key file> <options>
crypt1 /dev/sda6 none luks
This tells the system about the encrypted disks that are available. And the boot process will try to open them, and see if they contain the root file-system. In order for this to actually take effect at boot time, I also reinstalled the linux kernel, the initrd, and grub. (In my case I did it in the course of pending system updates, but one could also trigger package reinstalls manually with apt-get or synaptic.) From there on, the Ubuntu boot process has always asked me for a passphrase to access my disk, and booted flawlessly. Yeah!
Explanations and Implications
You might wonder, why one couldn’t adjust /etc/crypttab before or during the install? And, why a reinstall of the kernel is necessary? Well, maybe the first approach might work, but I didn’t test it. As for the kernel reinstall, it is not strictly necessary. The only thing that is strictly necessary is building a new initrd file, which will then contain its own copy of the above /etc/crypttab file. (I know there are other tools to achieve that, but a reinstall of the package seemed the easiest.)
But why is that necessary? And what is the initrd anyways? Well, you also might have been wondering how the boot process can access any configuration before the root file-system is mounted? Well, that’s where the initrd, the initial RAM disk, comes in: it contains all the files that are necessary for the boot-process, before the actual root file-system is available. That may be stuff like kernel-modules, low-level user-space tools (e.g. cryptsetup, lvm, BusyBox, etc.) and basic configuration files (e.g. fstab and crypttab). That’s why it is not sufficient to adjust the /etc/crypttab file in the actual root file-system. It is the /etc/crypttab inside the initrd that is relevant at boot-time!
After so much configuration hassle related to luks/cryptsetup, what about the layer above? What about lvm? Well, as you might have guessed by now, there is no further configuration necessary here. The lvm subsystem heavily relies on meta-data stored in the pvs, vgs, and lvs themselves. Apparently, the lvm kernel module together with the lvm user-land tools (from the initrd) automatically recognize the physical-volume /dev/mapper/crypt1 once it is created by cryptsetup. And lvm makes all the included logical-volumes available automatically, in particular the one containing the root file-system. Also, the installer already added a suitable entry for / in /etc/fstab. So this part of the problem seems to solve itself under Ubuntu.
Oh, one more thing: As you may have noticed, this approach leaves a couple of weaknesses open. In particular, the /boot partition itself is not encrypted. Neither is the grub code in the MBR. Or the partition table. This does not impose a huge problem, since those don’t usually contain any data that needs protection.
However, someone could tamper with them, when you leave your computer unattended! This might enable an eavesdropper to sniff your password. So when in doubt, you should probably re-install the /boot partition and the MBR! However, when someone has access to your computer, they might aswell tamper with the hardware. So I don’t consider this weakness overly relevant.