How To Use DM-Crypt to Create an Encrypted Volume on an Ubuntu VPS
This article covers a version of Ubuntu that is no longer supported. If you are currently operate a server running Ubuntu 12.04, we highly recommend upgrading or migrating to a supported version of Ubuntu:
- Upgrade to Ubuntu 14.04.
- Upgrade from Ubuntu 14.04 to Ubuntu 16.04
- Migrate the server data to a supported version
Reason: Ubuntu 12.04 reached end of life (EOL) on April 28, 2017 and no longer receives security patches or updates. This guide is no longer maintained.
This guide might still be useful as a reference, but may not work on other Ubuntu releases. If available, we strongly recommend using a guide written for the version of Ubuntu you are using. You can use the search functionality at the top of the page to find a more recent version.
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.
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
apt-get update apt-get install cryptsetup
This will pull in all of the required dependencies and helper utilities needed to work with a
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
/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.
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:
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
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:
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:
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 ls
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:
cd umount /mnt/files
This will detached the
/dev/mapper/volume1 location from our mount point at
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
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:
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:
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.