Encrypting Linux Root and Swap Drives Using ARM

In addition to encrypting regular data partitions on Azure, you can also encrypt your Linux root and swap partitions. Encrypting root and swap partitions ensures that clear-text data never leaves the VM on its way to storage. This prevents virtualization and storage administrators from being able to view any sensitive data.

Requirements

A separate boot disk is required on which the HyTrust software will be installed. This allows the system to boot and communicate with HyTrust KeyControl and get the necessary encryption keys which are then used to boot and decrypt (on the fly) the Linux root disk / file system and encrypt / decrypt / swap.

Make sure your version of Linux has a separate boot partition. If it does not you will need to create one. If the Linux installation does not have separate boot partition, we recommend that you create a free partition on the existing device. The procedure to set up a separate boot partition is different for different Linux platforms. Here we present the procedure for two flavors of Linux, CentOS and Ubuntu.

Common Preparation on any Azure Linux VM

Note: This discussion assumes that Azure is accessed through https://portal.azure.com. In the material that follows, we have created the VM through the Virtual Machines interface using the Azure Resource Manager (ARM) method.

The first part of the process for preparation of a separate boot partition is the same for both Linux flavors on the Microsoft Azure platform. We shall discuss this here.

Setting the Access Method

Ensure that the VM can be accessed using the ssh public key access method. It has been noticed that at times we lose VM access after the outlined process, and the only method that works for certain is the ssh public key access method. Although Azure allows you to change the access method at any time, it is best to set this before starting the process.

Click on Virtual Machine, and then click the + Add button at the top left. On the next tab, search for the machine to which you want access, and then click on that machine to install it. Select the deployment model as Resource Manager, which presents a dialog box in which to configure basic settings like VM name, Disk type, User Name, and SSH public key.

Release the OS Disk for the VM

There is no direct method to release the OS disk on Azure while keeping the VM intact. The only way to release the OS disk is to delete the VM.

As we delete the VM, any Azure customizations that we did for it will be lost with it. For this reason, before deleting the VM, you should make note of all required customizations, such as Resource Name, Storage Account name, VHD disk file name, Diagnostics storage account name, and so on.

Wait for Azure to delete the VM. The bar at the top of the Virtual Machine dialog box shows Deleting during the process, and you will receive a notification when the deletion is complete.

Resize the Root Partition

We need to create another VM in the same Resource Group in the same Location. Note that it is very important that the new VM be in the same resource group. Otherwise, it won’t be able to see the OS disk of the original VM. This second VM is used to modify the OS disk of the original VM. Linux does not support online resize of the mounted file system and that is the main reason for following this process.

The newly created partition is /dev/sdc3.

Attach the OS Disk to the New VM

Click on the Virtual machines tab, and it will list all machines. From the list, click on the New VM where you want to attach the disk of the original VM. Click the Disks tab, then Attach existing. Then select Storage Accountt, then VHD, and then the VHD file of the original VM. Set Host caching to Read/Write.

The OS disk will show up on the new VM, where you can use dmesg to find out the device name. In the case of a new Ubuntu 14.04 server, it shows as /dev/sdc. We need to resize the root file system on this device and create enough space for a separate boot partition.

Mount the root partition:

# mkdir /tmp/root
# mount -o ro /dev/sdc1 /tmp/root

Find out the space required by /boot subtree,

# du -sh /tmp/root/boot
178M    /tmp/root/boot
# umount /tmp/root

The new boot partition should at least have two times the amount of space used by /boot.

The following three steps are required to shrink the original root file system and create a new /boot partition.

# e2fsck -f /dev/sdc1
# resize2fs /dev/sdc1 <newsize>
# fdisk -u /dev/sdc 
Note: Assuming that the size of /dev/sdc1 is 10 GB originally, we have to cut out 500 MB (Considering max size of /boot) from it. The following is the example of the resize2fs command:

Example: # resize2fs /dev/sdc1 9G

Here, the filesystem size will get reduced by 1 GB, out of which 500 MB will be allocated to /boot.

We will have to delete and recreate the root partition, ensure that the new root partition starts at exactly the same block, and that its size is equal to or greater than the new size of the root file system (after we have run resize2fs). As a rule of thumb, the size of the new root partition should be 100 MB more than new size of the root file system. Remember to set the boot flag on the root partition.

Here is the actual output on a test machine:

root@prmub1604:~# e2fsck -f /dev/sdc1
e2fsck 1.42.13 (17-May-2015)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sdc1: 11/655360 files (0.0% non-contiguous), 79663/2621184 blocks
			
root@prmub1604:~# resize2fs /dev/sdc1 9G
resize2fs 1.42.13 (17-May-2015)
Resizing the filesystem on /dev/sdc1 to 2359296 (4k) blocks.
The filesystem on /dev/sdc1 is now 2359296 (4k) blocks long.

root@prmub1604:~# fdisk -u /dev/sdc

Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x3795c63b

Device     Boot Start      End  Sectors Size Id Type
/dev/sdc1        2048 20971519 20969472  10G 83 Linux

Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x3795c63b

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-20971519, default 2048): 2048 
Last sector, +sectors or +size{K,M,G,T,P} (2048-20971519, default 20971519): +9G
Created a new partition 1 of type 'Linux' and of size 9 GiB.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x3795c63b

Device     Boot Start      End  Sectors Size Id Type
/dev/sdc1        2048 18876415 18874368   9G 83 Linux

Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 2
First sector (18876416-20971519, default 18876416): 18876416
Last sector, +sectors or +size{K,M,G,T,P} (18876416-20971519, default 20971519): +500M

Created a new partition 2 of type 'Linux' and of size 500 MiB.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x3795c63b

Device         Boot    Start      End    Sectors  Size Id Type
/dev/sdc1      2048 18876415 18874368    9G 83         Linux
/dev/sdc2      18876416 19900415  1024000  500M 83     Linux

Command (m for help): a
Partition number (1,2, default 2): 1

The bootable flag on partition 1 is enabled now.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x3795c63b

Device     Boot    Start      End  Sectors  Size Id Type
/dev/sdc1  *        2048 18876415 18874368    9G 83 Linux
/dev/sdc2       18876416 19900415  1024000  500M 83 Linux

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
root@prmub1604:~# 

Now we have two partitions on the same disk: one is with 9 GB, and another for /boot with 500 MB.

Recreate the Original VM

After this step we need to detach the disk from the new VM, where we re-partitioned it to create the additional /boot partition.

The Azure Resource Manager Model doesn’t permit creation of a VM on an existing VHD using the webGUI. However, it can be done using the Azure python SDK. So to achieve that using the Azure python SDK, we have a script to create a VM on an existing VHD. The script is located at https://svn.hcs.int/svn/highcloud/trunk/not_shipped/azure/pyscript.

There are two files in the directory.

To get help on commands and parameters:

# python azurevm.py -h

The following is an example of a command used to create a VM:

# python azurevm.py -n prmct68-m2 -r prm -s prmdisks685 -d \
    prmct682016912173455 -l eastus2
Note: Make sure python and the Azure SDK are properly installed along with all required dependencies.

Once the machine is ready, log on to it and prepare the /boot partition.

Once the original VM is re-created, we can boot it and access it using the ssh public key access that we had set up in the first step.

Preparation of /boot on Ubuntu

From the new VM, format the new partition with ext4 or ext3. For example:

# mkfs.ext4 /dev/sda2

The files from the /boot directory should be copied to the new boot partition:

# mkdir -p /tmp/sda2
# mount /dev/sda2  /tmp/sda2
# cp -a /boot/* /tmp/sda2

Find the UUID of the new boot partition

# blkid -o list /dev/sda2
device        fs_type     label   mount point   UUID             
--------------------------------------------------------------
/dev/sda2     ext4               (not mounted)  b425c93b-533d-4e73-\ 8c2b-dbca05b9a8f1
			
# umount /tmp/sda2

Add an entry to /etc/fstab to mount the new boot partition, like this:

UUID=b425c93b-533d-4e73-8c2b-dbca05b9a8f1 /boot ext4 rw 0 0
Important: Mount the /boot partition. For example:
# mount /boot

Re-install grub on the current boot device (GRUB files need to be copied to /boot, which was mounted in the step shown above), like this:

# grub-install /dev/sda

Note that GRUB is being installed on /dev/sda but the boot directory comes from /dev/sda2. Update your GRUB configuration to take this change into account:

# grub-mkconfig -o /boot/grub/grub.cfg

Your system is ready now, so reboot and ensure that all is well.

Preparation of /boot on CentOS 7

Format the new partition with ext4 or ext3. For example:

# mkfs.ext4 /dev/sda2

The files from the /boot directory should be copied to the new boot partition:

# mkdir -p /tmp/sda2
# mount /dev/sda2  /tmp/sda2
# cp -a /boot/* /tmp/sda2

Find the UUID of the new boot partition:

# blkid /dev/sda2
# umount /tmp/sda2

Add an entry to /etc/fstab to mount the new boot partition, like this:

UUID=<uuid> /boot ext4 rw 0 0

Important: Mount the /boot partition. For example:
# mount /boot

Re-install GRUB on the current boot device (GRUB files need to be copied to /boot, which was mounted in the previous step), like this:

# grub2-install /dev/sda

Note that GRUB is being installed on /dev/sda but the boot directory comes from /dev/sda2. Update your GRUB configuration to take this change into account:

# grub2-mkconfig -o /boot/grub2/grub.cfg

Your system is ready now, so reboot and ensure that all is well.

Preparation of /boot on CentOS 6.8

Format the new partition with ext4 or ext3. For example:

# mkfs.ext4 /dev/sda2

The files from the /boot directory should be copied to the new boot partition:

# mkdir -p /tmp/sda2
# mount /dev/sda2  /tmp/sda2
# cp -a /boot/* /tmp/sda2

Find the UUID of the new boot partition:

# blkid /dev/sda2
# umount /tmp/sda2

Add an entry to /etc/fstab to mount the new boot partition, like this:

UUID=<uuid> /boot ext4 rw 0 0

Important: Mount the /boot partition. For example:
# mount /boot

Re-install GRUB on the current boot device (GRUB files need to be copied to /boot, which was mounted in the previous step). For example:

# grub-install /dev/sda

Note that GRUB is being installed on /dev/sda but the boot directory comes from /dev/sda2.

In CentOS 6.8, grub is installed, and not grub2. CentOS 6.8 does not provide a utility to update the /boot/grub/grub.conf file, so you need to update it manually.

The original grub.conf file, before modification, follows:

default=0
timeout=5
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
hiddenmenu
title CentOS 6 (2.6.32-642.1.1.el6.x86_64)
   root (hd0,0)
   kernel /boot/vmlinuz-2.6.32-642.1.1.el6.x86_64 ro root=UUID=8b9b4465-bdbf-4780-8b1e-d5b4d089a77d rd_NO_LUKS  KEYBOARDTYPE=pc KEYTABLE=us LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 console=ttyS0,115200n8 earlyprintk=ttyS0,115200 rootdelay=300 rd_NO_LVM rd_NO_DM
   initrd /boot/initramfs-2.6.32-642.1.1.el6.x86_64.img

The modified grub.conf file follows, with bold text for the lines that are changed:

default=0
timeout=5
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
hiddenmenu
title CentOS 6 (2.6.32-642.1.1.el6.x86_64)
   root (hd0,1)
   kernel /vmlinuz-2.6.32-642.1.1.el6.x86_64 ro root=UUID=8b9b4465-bdbf-4780-8b1e-d5b4d089a77d rd_NO_LUKS  KEYBOARDTYPE=pc KEYTABLE=us LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 console=ttyS0,115200n8 earlyprintk=ttyS0,115200 rootdelay=300 rd_NO_LVM rd_NO_DM
   initrd /initramfs-2.6.32-642.1.1.el6.x86_64.img

There are a total of three modifications:

Your system is ready now, so reboot and ensure that all is well.

Encrypting the Root and Swap Disks

At this point you are now ready to encrypt your root and swap partitions. First of all, to avoid having to repeat the process shown above, we recommend that you create a template from this VM. All subsequent VMs are then able to start with an already correctly partitioned system. See the following screenshot to understand how to create a template in Azure:

When you’re ready to encrypt your root and swap drives, see Encrypting Linux Root and Swap Drives.