LUKS and LVM

LVM + LUKS

LVM is software that uses physical devices as physical volumes (PVs) in storage pools called volume group (VG). Physical volumes can be a partition, whole SATA hard drive grouped as JBOD, RAID systems, iSCSI, Fibre Channel, eSATA, etc [1].

Whenever we decide we want to enable the LVM on the system, we first need to enable the following kernel options:

Device Drivers --->
Multiple devices driver support (RAID and LVM) --->
<*> Device mapper support
<M> Crypt target support
<M> Snapshot target
<M> Mirror target
<M> Multipath target
<M> I/O Path Selector based on the number of in-flight I/Os
<M> I/O Path Selector based on the service time

Then we need to compile the kernel for changes to take effect. We can compile the kernel with the make, then make modules and make modules_install commands. When the commands are executed successfully, we will have our new kernel at the location arch/x86_64/boot/bzImage in the /usr/src/linux/ kernel directory. We need to copy that kernel to the /boot partition before continuing, but if you're reading this guide you probably don't need an explanation of how to compile your kernel. If you're just reading the article for the sake of curiosity to learn a few things and don't actually want to configure your system with LVM support, you probably don't need to know the details, but if you want to know more you can read it on the official Gentoo website here: [2].

After the kernel is successfully compiled, the modules will be instantly available to the currently running kernel, so we can load then without restarting the system. But if we compiled the features as build-in, then we need to copy the kernel to the /boot partition and reboot the system for changes to take effect. After that, we must install appropriate LVM2 software packages in order to be able to work with LVM. To do that, we need to execute the commands below:

# emerge lvm2
# /etc/init.d/lvm start
# rc-update add lvm boot

The first command will install the lvm2 software package, while the second command will start it and the third command will start the lvm whenever booting the system.

When we receive a new partitionless hard drive, we can create a bunch of partitions on it go from there. But with LVM, this is not needed, since we can initialize a whole hard drive as PV (physical volume) and add it to the VG (volume group). Then we can manage the LVs (logical volumes) to create logical partitions that are not bound to the size of the physical partition lying below it. With LVM, the data will automatically be distributed onto all available PV (physical volumes - physical partitions).

Physical Volume - PV

The physical volumes are the actual hardware devices the LVM is built upon. To create a PV on an existing partition issue the following command:

# pvcreate /dev/sda1

To display all active PVs use the command below:

# pvdisplay

To remove a PV, we must first move all the data from chosen PV onto the other PVs, since the LVM automatically distributes the data over all PVs.

# pvmove -v /dev/sda1

Once this command is finished, there should be no data left on the PV /dev/sda1. Afterwards we can remove the PV from the VG and then remove the actual PV:

# vgreduce vg0 /dev/sda1
# pvremove /dev/sda1

Volume Group - VG

Volume groups must contain at least one PV, and are listed as /dev/<vg>/ devices.

To create a VG with a PV /dev/sda1:

# vgcreate vg0 /dev/sda1

List active VGs:

# vgdisplay

Extend the existing VG with a new PV named /dev/sda2:

# vgextend vg0 /dev/sda2

To remove a PV from the VG:

# pvmove -v /dev/sda1
# vgreduce vg0 /dev/sda1

To remove the VG:

# vgremove vg0

Logical Volume - LV

Logical volumes (LV) are created and managed in VG and are listed as /dev/<vg>/<lv> devices and can be used as normal partitions.

To create a LV named lvol1 in VG named vg0 with a size of 1GB use the following command:

# lvcreate -L 1G -n lvol1 vg0

Display all LVs:

# lvdisplay

Extend the LV lvol1 into 2GB size:

# lvextend -L 2G /dev/vg0/lvol1

Setting up LVM with LUKS

When we get our new hard drive, the first thing we need to do is create the partition scheme that we want to use. We can do this with the fdisk command. We won't go into the details about creating partitions with the fdisk, because this is out of scope of this article. If you want to read more about that, you can read documentation here: [3]. If you don't want to use fdisk, but would rather use a graphical user interface program, you can try gparted, which is really good and gets the job done.

After creating the partitions, we need to create the filesystem on the partitions. In our case, we'll create the XFS filesystem on the partitions. We could just as easily have used ext3 filesystem with using the mkfs.ext3 command instead of mkfs.xfs command. Note that we'll describe the whole process of using LVM with LUKS, not just the LVM part, since we need to be aware of the sequence of commands that need to be executed to use LVM and LUKS together.

We've already created the partitions and now it's the time to create an XFS filesystem on the partition with the following command:

# mkfs.xfs /dev/sda1

Once the filesystem is created, we need to encrypt the partition with cryptsetup. We've already describe this part in the previous tutorial, but we're exposing it again, because this needs to be done right after the filesystem creation. The command can be seen below:

# cryptsetup --verify-passphrase --cipher serpent-cbc-essiv:sha256
--key-size 256 luksFormat /dev/sda1

To open the encrypted partition, issue the luksOpen command:

# cryptsetup luksOpen /dev/sda1 root

Now is the time to create multiple logical partitions inside the single encrypted layer. This can be done with LVM. Let summarize what we've done: first, we created the partition scheme, and then we encrypted the chosen partition and opened the partition for writing. Now it's the time to create physical volume, which can be done with the command below:

# pvcreate /dev/mapper/root

We also need to create a new volume group (VG) with the command below (note that in our case the volume group will be named vg, but we can name it whatever we want; this is also the name that will be directly accessible under the /dev filesystem):s

# vgcreate vg /dev/mapper/root

At the end, we need to create needed logical volumes (LV). With the commands below, we're creating three logical volumes with the following names: swap, root, and home. The swap logical volume is only 2GB in size and will be used as a swap partition. The root logical volume is 60GB in size and will be used as a root partition, where we'll install the system on. The home logical volume is used for user's home directory partition, which will be mounted as /home/ and contains the rest of the space available on the hard drive.

# lvcreate --size 2G --name swap vg
# lvcreate --size 60G --name root vg
# lvcreate --extents 100%FREE --name home vg

The logical volume devices we created above are also created under the /dev/mapper/ directory.

# ls -l /dev/mapper/vg-*
brw------- 1 root root 253, 2 Oct 27 22:48 vg-home
brw------- 1 root root 253, 3 Oct 27 22:48 vg-root
brw------- 1 root root 253, 1 Oct 28 10:38 vg-swap

The names of the logical volumes are automatically prepended with the vg- string, which uniquely identifies the logical group and all its logical volumes (remember that the name of the logical group is vg, where the vg- comes from). Now it's the time to create filesystems on the logical volumes. Since those volumes are accessible via the mappings in the /dev/mapper/vg-*, we need to use the commands below to format the logical volumes to the XFS filesystem:

# mkswap /dev/mapper/vg-swap
# mkfs.xfs /dev/mapper/vg-root
# mkfs.xfs /dev/mapper/vg-home

Notice that we used the xfs filesystem and not ext3. This is not required and you can use ext3 if you like. This was done by the mere curiosity and benchmarking of the xfs filesytem.

After that, we can mount partitions on the system normally and install the operating system of our choice on them. If the LVs are already created and we restarted the system and need to enable the LVs again, we can do that with the following commands:

# vgscan
# vgchange -ay

This is the point to install the Gentoo operating system on the /dev/mapper/vg-root partition. This won't be described here, but a reader can get more information here: http://www.gentoo.org/doc/en/handbook/. After the system is installed, there are a couple of things we need to take care of before the system will be able to boot.

Conclusion

Now it's a good time to talk about how partitions are normally arranged when installing a Linux system. If we take a look at the picture below, we can see that we've presented three techniques of arranging partitions. The first mode is normal mode and shows how the partitions are normally arranged when the Linux system is installed. Usually, in normal mode we don't use any encryption to protect our data. In all modes we of course must have the MBR, which isn't really a partition, but the start of a disk to tell the booting process where the /boot partition is located. Usually we can change the MBR by overwriting the first part of the partition with the grub command. Next we have a /boot partition that must be unencrypted in all cases; in normal mode, the partitions are not encrypted anyway, but in the other two modes we have to have /boot partition unencrypted so the system can boot. If the /boot partition is encrypted, we need to provide a way to decrypt that partition before the booting process can continue; we can do that with having a keyfile stored on USB key, but most of the time this just complicates things considerably and we're not going to describe it here. The second mode is LUKS mode, where all partitions except the /boot are encrypted with a password. In this mode, the partitions are visible if we do fdisk -l, but are encrypted and they need to be decrypted when booting a system. In LUKS+LVM mode we have a LVM partition setup, which contains three logical volumes: swap, root and home. In this scenario we first need to decrypt the LVM partition (as we decrypted every partition in the LUKS mode), and then issue additional commands to detect the logical volumes in the LVM partition. Once the volumes are detected and their mappings are created in the /dev/mapping/ we can boot off the vg-root logical volume normally.

image0|

We also need to mention that whenever we need to decrypt the system partition to boot up from, we need to have an initrd image, which will do that when the system boots. The system itself cannot know how to decrypt the partitions by itself, we must include the initrd image in the grub.conf, which is read in early userspace, and decrypts the partitions and boots from the decrypted system partition. We'll discuss that in more detail in the next tutorial.

References:

[1]: LVM (Logical Volume Manager), http://wiki.gentoo.org/wiki/LVM.

[2]: Configuring the Kernel, http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=1&chap=7.

[3]: Preparing the Disks, http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?chap=4&part=1.

Comments