Archive for January, 2008
Encrypting a root partition with RHEL5 – HOWTO
The number of stolen laptops only continues to grow every year. It’s not surprising then, that employers and organizations are particularly concerned about the risk of their data, many times proprietary or confidential, falling prey to adversaries, or even the general public, causing much harm to them, their image, and their ability to protect vital assets.
Strangely enough, my employer doesn’t require all our laptops to be entirely encrypted, what we refer to in our lingo as encrypted at rest. I decided that I wasn’t going to fall prey to our lack of guidance, and implement an encrypted root partition protected by a passphrase on my laptop. Because we are mainly a Red Hat Enterprise Linux shop, this HOWTO is geared towards getting RHEL5 up and running with an encrypted root partition. Sadly enough, in my research for finding a solution, neither Red Hat nor the Fedora project has implemented a completely automated way for doing this, which I hope will change (and there is a lot of talk about it). In a perfect world, there should be an option within the Anaconda installer to encrypt whatever partitions you want when you build a system.
Overview
We’re going to use LUKS, cryptsetup, and device-mapper to encrypt our root partition. Basically, to do this, we have to have an installed copy of RHEL5 on an unencrypted partition with LVM first. Essentially, we will move the data of that install block by block over to an encrypted partition that we create, then configure our bootloader and initramfs to boot off this partition instead. To do that, we’re going to need a minimum of 3 partitions, one to hold the initial installed copy, another (important!) larger partition for the eventual encrypted partition, and third an unencrypted (100MB is enough) partition to hold /boot so that we can boot up. Use fdisk to create the partitions, or do it when you install the system. Here’s my output of fdisk.
Disk /dev/sda: 80.0 GB, 80026361856 bytes 255 heads, 63 sectors/track, 9729 cylinders Units = cylinders of 16065 * 512 = 8225280 bytesDevice Boot Start End Blocks Id System /dev/sda1 1 5905 47431881 83 Linux /dev/sda2 * 5906 5918 104422+ 83 Linux /dev/sda3 5919 9729 30611826 8e Linux LVM
Create the encrypted volume
Once you have your RHEL5 system installed on the smaller partition, make sure you’ve installed all the latest Red Hat updates, particularly the kernel. Every time you want to install a new kernel, you’re going to have to rebuild the initrd manually. Just keep that in mind.
Next, if you haven’t done so already, create the larger partition which will hold the eventual encrypted root volume. The type of the partition should be Linux, or type 83, not Linux LVM, even though we will be using LVM over this. To the OS, the actual partition will not be used. Indeed, it’s encrypted, so it’s unintelligible to anyone without the key. Instead, device-mapper creates a virtual mapping of the unlocked partition, and the OS writes to these logical volumes. Cryptsetup takes care of all of the decryption and encryption for device-mapper when the kernel is writing and reading. This is the crux of how disk encryption works on kernel 2.6.x. Cryptsetup, using the LUKS extension to pull the partition encryption header information, prompts you to unlock the volume, asking device-mapper to setup a virtual mapping that the OS will then use to write data to.
In creating the encrypted volume, while not necessary, it’s highly recommended that you randomize the data on /dev/sda1. This makes it many times more difficult for someone to guess the key that you use. Because it’s very processor heavy to create truly random numbers, this will take quite a while, depending on your cpu and the size of your partition. For me, it was writing at about 2.7 MB/s average. Run dd or shred (insuring you’re blowing away the correct partition!), and take a break.
# dd if=/dev/urandom of=/dev/sda1…wait a while…
Now that the real partition is randomized, simply create the encrypted partition. It will ask you to setup a passphrase at this time. Do NOT forget it!
# cryptsetup --verify-passphrase --key-size 256 luksFormat /dev/sda1
Migrating the data
Next, we will migrate the data over to the encrypted volume. You’re going to need a way to run your machine without mounting your current RHEL5 installation’s root partition – I used Fedora 7 Live CD to do this. Reboot your machine into Fedora Live and open your newly created encrypted partition, like this.
# cryptsetup luksOpen /dev/sda1 cryptpv
This opens up the volume and creates a device mapping at /dev/mapper/cryptpv that will become our new physical volume for lvm. Next, verify that Fedora sees your existing Volume Group on /dev/sda3.
# vgdisplay vg00
Now, initialize the encrypted device as a physical volume, and add it to your volume group.
# pvcreate --verbose /dev/mapper/cryptpv # vgextend --verbose vg00 /dev/mapper /cryptpv
Next, use pvmove to migrate the logical volumes over to the new encrypted disk. Since this is the part that is actually moving all of your data, it will take a while. Use the –verbose flag to see what it’s doing. Pvmove is the reason why we need the live cd, it can’t move a live root partition.
# pvmove /dev/sda3 /dev/mapper/cryptpv
Make sure that the move has finished! Now you can remove the “empty” physical volume from the pool. If you did everything correctly, you shouldn’t have any problems.
# vgreduce --verbose vg00 /dev/sda3 # pvremove --verbose /dev/sda3
Creating the modified initrd
Now that all of our data is on the encrypted disk, all that’s left is to create a new initramfs for our bootloader to load and properly find our new encrypted root partition. There are many ways already documented on how to create the modified initrd image – I decided to build it manually. It’s not that hard, and rather than patch your mkinitrd script, which will get overwritten on the next update, it feels simpler for me at the moment.
First, let’s chroot to our installation (and backup our lvm’s metadata).
# swapoff -a # mkdir /mnt/tmp # mount /dev/vg00/root /mnt/tmp # cp -ax /dev/* /mnt/tmp/dev # chroot /mnt/tmp (chroot) # mount -t proc proc /proc (chroot) # mount -t sysfs sysfs /sys (chroot) # mount /boot (chroot) # swapon -a (chroot) # vgcfgbackup
The kernel needs to be able find the logical volumes, so first we need to make sure init loads a couple of additional modules for cryptsetup: dm-crypt, aes, and sha256. Modify (or create) /etc/sysconfig/mkinitrd file, and add the following:
MODULES="aes sha256 dm-crypt"
Now, run mkinitrd with the latest kernel that your installation is using. At the time of this writing, RHEL5 was at 2.6.18-53.1.4.el5.
(chroot) # mkinitrd -v /boot/initrd-2.6.18-53.1.4.el5-tmp-crypt.img 2.6.18-53.1.4.el5
Extract the newly created image in /boot.
(chroot) # mkdir /boot/initrd-2.6.18-53.1.4.el5-crypt.dir (chroot) # cp /boot/initrd-2.6.18-53.1.4.el5-tmp-crypt.img initrd-2.6.18-53.1.4.el5-crypt.dir (chroot) # cd /boot/initrd-2.6.18-53.1.4.el5-crypt.dir (chroot) # gunzip < initrd-2.6.18-53.1.4.el5-tmp-crypt.img | cpio -ivd
Now, you need to modify init by adding the following lines after the line which reads “mkblkdevs” and before “echo Creating root device.”:
echo Decrypting root device cryptsetup luksOpen /dev/sda1 cryptpvecho Scanning logical volumes lvm vgscan --ignorelockingfailure echo Activating logical volumes lvm vgchange -ay --ignorelockingfailure vg00
Lastly, you need to recreate initrd.
find ./ | cpio -H newc -o | gzip -9 > /boot/initrd-2.6.18-53.1.4.el5-crypto.img
Altering grub.conf
The last step is to make sure that your grub configuration file is updated to point to the new initrd image. Add an entry like below to /boot/grub/grub.conf.
title RHEL5 Encrypted Server (2.6.18-53.1.4.el5) root (hd0,2) kernel /vmlinuz-2.6.18-53.1.4.el5 ro root/dev/vg00/root rhgb initrd /initrd-2.6.18-53.1.4.el5.crypto.img
Now, unmount and exit chroot, then reboot. Voila!!
(chroot) # swapoff -a (chroot) # umount /boot (chroot) # umount /proc (chroot) # umount /sys (chroot) # exit # umount /mnt/tmp
A couple extra items
As always, there are a couple of extra things to note. Depending on your hardware, you may encounter this same problem as myself when booting from your new initrd.
Can't open device: /dev/xxx
After some searching online and head scratching, I found that I also needed to include the specific module of my SATA chipset in order for the kernel to find the device. Make sure you add whatever extra modules are needed by your hardware to /etc/sysconfig/mkinitrd/modules and rebuild mkinitrd.
For the Super Secure
There is of course one flaw with regards to this entire process for safeguarding your data. The /boot partition is unencrypted and writable, so someone could install a keylogger and unbeknownst to you, capture your passphrase and defeat the entire secure mechanism. To protect against that, simply make a bootable cd and boot from that instead. That way, you can assure yourself that you’re running only the code that you assumed to be running. In this case, I’m going to use ISOLINUX, which is the bootloader that comes with the RHEL5 CDs.
Mount the RHEL5 disc1 and copy the isolinux.bin file in the isolinux/ directory to an identically named directory of your own.
mkdir -p /tmp/bootcd/isolinux cp /mnt/cdrom/isolinux/isolinux.bin /tmp/bootcd/isolinux/isolinux.bin
Copy your initrd image and compressed kernel (vmlinuz) to the directory as well. Be sure to name them initrd.img and vmlinuz. While you *can* name them whatever you want, isolinux only uses the “plain” ISO 9660 filenames, i.e. it does not support Rock Ridge or Joliet filenames. It didn’t matter to me so much how they were named, so I went with what I know works.
cp /boot/initrd-2.6.18-53.1.4.el5.crypto.img /tmp/bootcd/isolinux/initrd.img cp /boot/vmlinuz-2.6.18-53.1.4.el5 /tmp/bootcd/isolinux/vmlinuz
Next, create an isolinux.cfg configuration file in the isolinux directory with the following:
default cryptolinux prompt 1 timeout 600 label cryptolinux kernel vmlinuz append initrd=initrd.img
You can add a display and a splash screen too if you want. More details are on the isolinux website. Also, use the items in the RHEL5 isolinux directory as well as a guide.
Lastly, create the iso and add a checksum. Then, burn it to disk!
4 comments$ cd /tmp/bootcd $ mkisofs -J -R -v -T -o myBooter.iso -b isolinux/isolinux.bin -c isolinux/boot.cat \-no-emul-boot -boot-load-size 4 -boot-info-table . $ /usr/lib/anaconda-runtime/implantisomd5 --force myBooter.iso
Hello world!
I’ve been meaning to start a personal blog for the past five years, having had a clue to what they were before the entire world jumped on them (it still makes me a band wagoner today though), and I’m excited that I’ve finally made this day a reality. Even after having had five years to think about it, strangely enough, I still couldn’t tell you what I’m going to write about, let alone come up with a title that captures that ethos in a consistent theme. “Ramblings of a Curious American” was all I could muster up – instead, I’m going to review what I write about over time and pave the road where the people end up walking.
In real life, people regularly want to know my opinion about things, so even though I realize I’m adding yet another voice to the sea of plentiful noise now dubbed the blogosphere, they must be something of value I write about to someone. I’m hoping, anyway.
In the meantime, as a Software Engineer, the title couldn’t have been better for a first post, “Hello World”!
No comments
