We hope you find this tutorial helpful. In addition to guides like this one, we provide simple cloud infrastructure for developers. Learn more →

How To Use DM-Crypt to Create an Encrypted Volume on an Ubuntu VPS

Posted Apr 7, 2014 95.5k views Security Ubuntu


Security should be a primary concern for any kind of data that stored on an internet accessible computer. While every storage provider should take care to secure data from their end, this only goes so far as unauthorized access can happen through software flaws of services on your server, social engineering, and many other avenues. In short, you should take ownership of the encryption and security of any data that you cannot afford to fall into the wrong hands.

There are many ways to encrypt content on a Linux system. Many of these options rely on encrypting separate partitions, devices, or filesystems. This may not be an option if you are dealing with a system like a VPS. However, there are other options, such as creating a file that operates as a device in order to store encrypted data.

In this guide, we will use the dm-crypt tools to create a large encrypted file that can be used to store our sensitive data. We can then mount this file as if it were a regular partition. We will be demonstrating this on an Ubuntu 12.04 VPS instance, but similar procedures should work for other distributions.

Basic Idea

The dm-crypt is a kernel-level encryption mechanism which offers transparent disk encryption. This means that the files are immediately available without any additional interaction after mounting.

While most encryption schemes rely on encrypting things at the partition level, we can get around this by using a file that we mount as a device mapping target. We do this by mounting the file as a loop device. We can then store data on this mounted "device" just like we would with any other partition or device.

When considering implementing any kind of encryption, you need to weigh some pros and cons. First of all, there is always a performance overhead involved with encryption. This may or may not be significant, and we recommend that you create a small file first to run tests against before implementing this on a larger scale.

Another consideration is recovery. Encryption, by virtue of its primary function, makes recovery more difficult. If you forget your password, your data is effectively lost forever. If your LUKS header is overwritten or damaged, your data is also lost forever. If your system is not booting and you need to access information in your encrypted file, you will have to go through a more complex process to gain access.

When making a decision to encrypt data, you need to be aware of the possibility of losing that data if something goes wrong. You should definitely backup any of the data, and dm-crypt provides a lot of information about how to do that here.

Installing the dm-crypt Tools

While the kernel-level functionality should be available in your distribution, the actual front-end tools probably are not installed by default. All of the commands in this guide will be performed as root.

We can get the necessary tools by updating our local package index and installing the dm-crypt tools:

apt-get update
apt-get install cryptsetup

This will pull in all of the required dependencies and helper utilities needed to work with a dm-crypt volume.

Create a Non-Sparse Empty File

To store our encrypted data, we need to create a file which will act as our storage device.

We want to create an empty file, but we can't have that be a sparse file, which doesn't actually allocate the full file size when it is created. We can do this in a variety of ways.

The easiest and the quickest way of going about this operation is with the fallocate command. This instantly allocates the amount of disk you would like for a file and assigns it the filename you give it.

For instance, to create a 512MB file on in our root user's home directory, we can type:

fallocate -l 512M /root/test1

This is incredibly fast, but it does have a disadvantage that it will not overwrite whatever old, deleted data that used to be used by those blocks with zeros or random data. This probably will not be desirable for your purposes because we don't want people to be able to tell which portion of the file has encrypted data written to it.

Another alternative is using the ubiquitous dd command. We can write zeroes to the entire area that we are provisioning to our file by using the /dev/zero pseudo-device. We could create a similar file to the one above by typing something like:

dd if=/dev/zero of=/root/test2 bs=1M count=512

If instead, you would like to write random data, which should mimic the encrypted data that will actually be written to it, you can use one of the random pseudo-devices instead. This will take quite a lot longer, especially if you are allocating a large file, but using the random devices is probably is the best way to provision a file for this purpose:

dd if=/dev/urandom of=/root/test3 bs=1M count=512

Using the /dev/random pseudo-device is an even more secure way of doing this, again at the expense of time:

dd if=/dev/random of=/root/test4 bs=1M count=512

Creating a dm-crypt LUKS Container in the File

Before we format the file that we just created, we should create a LUKS partition within the file. LUKS, or Linux Unified Key Setup, is a standard for disk encryption. This is the basic layer that all of our other data will sit on top of.

The dm-crypt tools provide a very easy way to create this layer. We can create the container with this command.

cryptsetup -y luksFormat /root/test1

You will need to confirm that you wish to overwrite the contents of the file. Double check the file you are referencing so that you do not accidentally overwrite the wrong file. When you have confirmed, type "YES" to continue.

You will then be asked to set a password that will be needed to decrypt the data. Remember: if you lose this password, any data saved into the filesystem that we will create will be lost. Securely store this password somewhere where it will not be lost or be sure to remember it. The -y option will allow us to verify the password to make sure that we haven't made any mistakes.

If we check out the file now, we can see that it is now known as a LUKS encrypted file:

file /root/test1

test1: LUKS encrypted file, ver 1 [aes, cbc-essiv:sha256, sha1] UUID: 1851db36-3223-4ee1-8e3e-cc65c49e05f3

Now that we have the container built on top of our file, we can open the container like this:

cryptsetup luksOpen /path/to/LUKS/file mapping_name

In our case, we will use our /root/test1 file and name it volume1:

cryptsetup luksOpen /root/test1 volume1

You will have to supply the password you set for the file, which is needed to decrypt it.

This opens the LUKS device, and maps it to a name that we supply, in our case creating a file at /dev/mapper/volume1. This basically opens the file as a local loopback device so that the rest of the system can now handle the file as if it were a real device.

Creating and Mounting the File System

Now that we have a LUKS container created and it is opened as a regular device in our system, we can begin doing regular device operations on it.

First, we need to format and create a filesystem on our device. You can choose whatever filesystem you'd like. We will use a standard Ext4 filesystem, but you can use any filesystem that your server is configured to handle normally.

For our purposes, the command we want to use is:

mkfs.ext4 -j /dev/mapper/volume1

We now have a filesystem written on top of our LUKS container that is contained in our file. Since it is being handled like a device, our next step is logically to mount the device.

Let's create a mount location that will make sense:

mkdir /mnt/files

Now, we just need to mount our filesystem:

mount /dev/mapper/volume1 /mnt/files

You can now see our file as part of our available filesystems:

df -h

Filesystem           Size  Used Avail Use% Mounted on
/dev/vda              59G  2.7G   54G   5% /
udev                 2.0G   12K  2.0G   1% /dev
tmpfs                791M  216K  791M   1% /run
none                 5.0M     0  5.0M   0% /run/lock
none                 2.0G     0  2.0G   0% /run/shm
/dev/mapper/volume1  486M  2.3M  459M   1% /mnt/files

You can see that some of the available space in our file has been taken up by the encryption overhead and the filesystem overhead. We still have most of our space though.

If we check out the location that we've mounted our file, we can see that it's been provisioned exactly like any other Ext4 filesystem:

cd /mnt/files


The normal lost+found recovery directory has been created. We can now write data to this location, and it will be placed, encrypted, in our file. For example, we can just take our /etc directory and copy it into the mount location:

cp -r /etc/* /mnt/files

Unmounting the Filesystem and Closing the LUKS Container

When we are finished writing or reading our data, we unmount the filesystem using the normal methods:

umount /mnt/files

This will detached the /dev/mapper/volume1 location from our mount point at /mnt/files:

df -h

Filesystem      Size  Used Avail Use% Mounted on
/dev/vda         59G  2.7G   54G   5% /
udev            2.0G   12K  2.0G   1% /dev
tmpfs           791M  216K  791M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            2.0G     0  2.0G   0% /run/shm

However, our file is still open and available to the system as /dev/mapper/volume1.

ls /dev/mapper/

control  volume1

The control device is a device that is used to create other mapped devices. We can safely ignore this, as it is supposed to be here.

To close the volume1 file and secure its contents, we have to close the file, basically removing the device mapping from the file. This means that you will no longer be able to access the content of the file until you supply the password again:

cryptsetup luksClose volume1

If we check our device mapping directory, we will see that our volume1 device has been removed:

ls /dev/mapper


Our volume is now unmounted, the LUKS container is closed, and our data is completely encrypted and secured behind our password.

Straight Forward Usage Procedure

To separate the initial creation procedures from the daily usage, we'll quickly run through the process that you'd need to take to use the file.

Now that you have the LUKS file, when you want to use it, you can simply open the LUKS file:

cryptsetup luksOpen /root/test1 volume1

You can choose a different name here than you used the first time, it will only matter as long as the file is open. Enter the password for the volume.

Afterwards, mount the device that has been mapped:

mount /dev/mapper/volume1 /mnt/files

You can now access and read or write to the contents of the file.

When you are finished, you'll have to unmount the device again:

umount /mnt/files

Once the device is unmounted, you can close the LUKS file again to encrypt the data:

cryptsetup luksClose volume1


You should now have the ability to create an encrypted file to store your sensitive data. Remember that there is often a trade off between performance and ease-of-use and security. Also, keep in mind that you must never lose the password you set, because there is absolutely no way of recovering it.

While this is not the only consideration necessary to protect your data, hopefully you can add this to your toolbox in order to tighten up security on your Linux servers.

By Justin Ellingwood


Creative Commons License