Monthly Archives: October 2017

Using Clevis/Tang to do Volume Encryption in OpenStack

Nathaniel McCallum has been working for awhile now on a new mechanism to automate the unlocking of encrypted disks in a data center.  The idea is that as long as the disk remains in the data center – or more specifically, accessible to an encryption server  – on what is presumably a trusted network – the disk can be automatically unlocked.  More importantly though, the disk cannot be unlocked without access to the encryption server.

I say encryption server rather than key server, because the server does not actually store any volume keys.  There is no escrow.

Lets explore a little about how the McCallum Relyea exchange works, and why its so cool.


The math looks complicated, but it really isn’t.  Lets break it down a bit.

In the provisioning step, the server generates a key pair with private key S and public key s.  It then advertises the public key s.  The client also creates a key pair with private key C and public key c.

It then creates a symmetric key K using the server public key s and its own private key C.  Note that this is the same symmetric key that the server would create in the Diffie Hellmann exchange if it knew the client public key.

client: K = sC =  gSC          server: K = cS = gCS  = gSC

In this case, though, the client does not advertise its public key c, which means that only the client can derive K.  It uses K as a KEK for the volume and writes it in one of the LUKS slots.  It then discards K and its private key C — which means that it can no longer derive K – at least without the help of the server.

In the recovery step, the client generates a new key pair and combines that key with the client public key.  Based on what comes back from the server, the client can derive K, because:

K = y – sE = xS – gSE = (c+e)S – gSE = (c +gE)S – gSE = cS +gES -sSE = cS

A couple of notes:

  • During provisioning, only the server public key is needed.  The server does not even need to be online.  You could for instance put the public key in a kickstart file.
  • There is no state on the server.  No keys are transferred.  No escrow.
  • All of the stuff that is transferred (s,x,y) are either public or meaningless to an eavesdropper, so no TLS/encryption of the channel is required.

So what about OpenStack?

This is all great for the data center, where you have a trusted network.  But what about OpenStack.  How can you make an encryption server (Tang server) act like its on a local trusted network?  Nathaniel came up with a suggestion on how to do that too — using VPNs!


So, in this case, the Tang server looks like it is on the local network.  You could even configure the VPN to provide an IP for the Tang server that is on a private subnet in your tenant.  This totally solves the BYOK scenario.

Proof of Concept

In preparation for the OpenStack summit in Sydney, I did a basic proof of concept.  The goal here was to show that a local Tang server could be used to automatically decrypt volumes in an OpenStack deployment.

At this point, Tang/Clevis only supports the encryption of root volumes, so we had to test those volumes only,  I expect Tang/Clevis to be even more useful — and easier to integrate for non-root volumes when that support is added.

Step 1: Set up a Tang server

This is dead easy.

  • Create a Nova instance using a Centos 7.4 or RHEL 7.4 image.
  • Install and start the tang server
    • $ sudo dnf install tang
    • $ sudo systemctl enable --now tangd.socket

Step 2: Create a Provisioned Volume

The steps here are probably a bit more complicated than they need to be.  When I have time, I’ll go back and make them simpler and more consumable – ie. using CLIs and kickstarts., rather than using horizon.

  • Upload a Centos 7.4 ISO to glance.  Be sure to use the ISO type.  I used a minimal ISO. ( )
  • Create an empty volume in cinder.  In this case, I created one that was 10G large.  We’ll call this Vol1.
  • Create an instance in Nova using the ISO as the base image.
  • Attach Vol1 to that image.
  • Connect to the instance console.  The instance should boot into the anaconda install.
  • For the disk partitioning, add Vol1 and create two partitions –
    • A boot partition (/boot) of 256MB).  This partition MUST be unencrypted.
    • The rest as the root volume (/).  Be sure to select this volume to be encrypted and provide a passphrase.
  • Set the root password and complete the installation.
  • Now detach the (now no longer empty) Vol1 from the instance and set it to bootable.
  • Destroy the old instance.
  • Create a new instance with Vol1 as the base image.
  • Once the instance has spawned, log on through the console as the root user.  You will need to type in the LUKS password for the server to come up.  We are now going to install clevis, rebuild the initramfs and provision the volume with the Tang server.
    • ifup eth0
    • yum install wget clevis-dracut
    • change /etc/sysconfig/network-scripts/ifcfg-eth0 to enable the network on boot. (ONBOOT=yes)
    • Rebuild the initramfs:
      • dracut -f
    • Register with Tang:
      • clevis bind luks -d /dev/vda2 tang ‘{“url”:”http://<tang server ip>”}’
    • Reboot

Step 3: Test Away!

At this point, you can reboot the test instance and see that the server will automatically boot and mount the encrypted root volume when the tang server is up.

You can also shut down the Tang server and see that the instance boot process stops at the prompt to provide the LUKS password.  QED