VM Disk Encryption Keys

In this article, we'll guide you through the process of preparing Vault for storing our LUKS keys and obtaining the necessary details to integrate hosts with Vault. Additionally, we'll aim to conclude by setting up a client to test the entire system. To facilitate this, you should have set up a new VM and added an additional disk to it within a cluster.

Approle

To begin, we'll create a new backend on Vault using Approles instead of the KV store. Approles are particularly useful for machine or service authentication rather than human users.

Normally, we'd require the approle_id and the secret_id to obtain a valid token from Vault. However, in our current setup, only the approle and being within the specified CIDR range are necessary. Here's the command used:

vault write auth/approle/role/vaultlocker bound_cidr_list=192.168.0.0/24 token_bound_cidrs=192.168.0.0/24 policies=vaultlocker

This command creates an approle named "vaultlocker" with the associated policy "vaultlocker" (which we'll create shortly) and restricts access to my internal network.

Next, we need to create the policy.

Policy

We need to define a policy for this approle. Here's the policy:

path "/vaultlocker/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}

After creating the policy, rerun the approle creation command.

That should cover the necessary configurations.

Vaultlocker

The script we're utilizing, called Vault Locker, appears to be part of the OpenStack suite. It's a relatively small Python script but seems to function effectively.

Installation

Installation is straightforward; you can install the vaultlocker using pip.

pip install vaultlocker

Additionally, you'll need to create the config directory and file:

mkdir /etc/vaultlocker
touch /etc/vaultlocker/vaultlocker.conf

Vaultlocker.conf

Configuration for vaultlocker is stored in /etc/vaultlocker/vaultlocker.conf. It's a simple file containing three key pieces of information. Here's a sample configuration with the IDs omitted:

[vault]
url = http://vault.xxx.host
approle = qqqqq-wwww-eeee-rrr-ttt-yyyy
secret_id = yyy-ttt-rrr-eee-wwww
backend = /vaultlocker

You can retrieve your approle ID using the following command:

vault read auth/approle/role/vaultlocker/role-id

which will output the approle ID.

[jon@jons-laptop ~]$ vault read auth/approle/role/vaultlocker/role-id
Key        Value
---        -----
role_id    qqqqq-wwww-eeee-rrr-ttt-yyyy

If you've used the provided command to create the approle, the secret ID isn't necessary.

The backend refers to the path where data is stored.

Run

Let's put our setup to the test.

Firstly, we need to gather some information about the disk we intend to encrypt, ideally its UUID. For testing, here we'll be using /dev/sdb1. You can check in /dev/disk/by-uuid to find the UUID of your disk:

[root@test ~]# ls -lash /dev/disk/by-uuid/
total 0
0 drwxr-xr-x. 2 root root 140 Nov 10 03:53 .
0 drwxr-xr-x. 6 root root 120 Nov 10 03:53 ..
0 lrwxrwxrwx. 1 root root  10 Nov 10 03:53 09a0896e-6e60-47d8-a51c-a538b94db494 -> ../../sda1
0 lrwxrwxrwx. 1 root root   9 Nov 10 03:53 2019-09-11-18-50-31-00 -> ../../sr0
0 lrwxrwxrwx. 1 root root  10 Nov 10 03:53 65242782-090c-44ab-8808-289b5903a6a6 -> ../../sdb1
0 lrwxrwxrwx. 1 root root  10 Nov 10 03:53 e45b5102-c583-4b96-805b-b52a4c440ce4 -> ../../dm-0
0 lrwxrwxrwx. 1 root root  10 Nov 10 03:53 ef376ffc-983c-4cab-859a-2b8d6ba5faf5 -> ../../dm-1

Now that we have the UUID, let's proceed with encrypting it and verifying if the LUKS key is sent to Vault! Run the following command, replacing the UUID and block device with your own:

[root@test ~]#  vaultlocker encrypt --uuid 65242782-090c-44ab-8808-289b5903a6a6 /dev/sdb1

You should receive an output similar to this:

DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): vault.haynet.host:80

DEBUG:urllib3.connectionpool:http://vault.haynet.host:80 "POST /v1/auth/approle/login HTTP/1.1" 200 487

INFO:vaultlocker.dmcrypt:LUKS formatting /dev/sdb1 using UUID:65242782-090c-44ab-8808-289b5903a6a6

INFO:vaultlocker.dmcrypt:udevadm trigger block/add for /dev/sdb1

INFO:vaultlocker.dmcrypt:udevadm settle /dev/disk/by-uuid/65242782-090c-44ab-8808-289b5903a6a6

DEBUG:urllib3.connectionpool:http://vault.haynet.host:80 "POST /v1/vaultlocker/test.haynet.host/65242782-090c-44ab-8808-289b5903a6a6 HTTP/1.1" 204 0

DEBUG:urllib3.connectionpool:http://vault.haynet.host:80 "GET /v1/vaultlocker/test.haynet.host/65242782-090c-44ab-8808-289b5903a6a6 HTTP/1.1" 200 864

INFO:vaultlocker.dmcrypt:LUKS opening 65242782-090c-44ab-8808-289b5903a6a6

INFO:root:Enabling systemd unit for vaultlocker-decrypt@65242782-090c-44ab-8808-289b5903a6a6.service

Created symlink from /etc/systemd/system/multi-user.target.wants/vaultlocker-decrypt@65242782-090c-44ab-8808-289b5903a6a6.service to /usr/local/lib/systemd/system/vaultlocker-decrypt@.service.
[root@test ~]# 

I've added line breaks for readability. In summary, it worked flawlessly!

It successfully accessed the Vault cluster, formatted the disk, encrypted it, and then extracted the hostname of the machine. Afterward, it created a new secret in the /vaultlocker backend, storing the LUKS key under the disk's UUID.

Let's verify this in the UI:

Now, onto the final step... mounting at boot.

Setting up the service file

Vaultlocker has generated a systemd service file for us. While the current configuration decrypts the device on boot, we also want it to mount. Let's add the mount command to the service file:

[Unit]
Description=vaultlocker retrieve: %i
DefaultDependencies=no
After=networking.service

[Service]
Type=oneshot
KillMode=none
Environment=VAULTLOCKER_TIMEOUT=10000
ExecStart=/bin/sh -c 'vaultlocker --retry $VAULTLOCKER_TIMEOUT decrypt %i && /usr/bin/mount -t ext4 /dev/mapper/crypt-65242782-090c-44ab-8808-289b5903a6a6 /test'
TimeoutSec=0

[Install]
WantedBy=multi-user.target

This addition ensures that the device is mounted to /test after decryption.

With these steps completed, your setup should be ready for use.

Last updated