Log in

No account? Create an account
entries friends calendar profile Previous Previous
Setting up NBDE in Centos - Ed's journal
Setting up NBDE in Centos

A new feature in RHEL and Centos 7.4+ is the Network Bound Disk Encryption.

Specifically - it extends a LUKS encrypted volume, such that you can use some servers on the local network to perform the decryption automatically.

And in particular - this can be done on root volumes, meaning that _all_ of your 'at rest' data is encrypted. 

Why encrypt root? 

- Cloud hosts - you might very well want to have proprietary information encrypted at rest when being hosted in the cloud

- Desktops - if your machines are physically accessible they can be stolen or have drives removed. (Or just booted into 'recovery' mode and bypass audit controls)

- Laptops - losing them on the train. 

But all these things come with a pretty significant drawback - in order to reboot them, you need someone to physically enter a password a boot time. That ends up being a pretty big problem if you - for example - want to patch and restart a batch of servers. 

So enter NBDE - the client 'talks' to some servers on the local network, and uses a key exchange to generate a passphrase for drive decryption. It can do this at boot time, by enabling the network and appropriate modules in dracut

Centos/RHEL 7.4+ ship with the packages needed to do this: 

Clevis (and clevis-dracut) for the client side decryption.

Tang - the authentication/decryption server.

To set this up you will need 3 things:

A test host that you can reformat to encrypt as 'client'

A decryption server (to run tang). Ideally 2 - or more - for resilience. 

Kickstart configured. (You can set this up on a 'test' partition if you like, but sooner or later you'll need to be rebuilding to reformat the root drive)

So first - setup your 'tang' server. I'd recommend having 'a few' for resilience reasons. Also the documentation suggests running a http reverse proxy 'in front' for performance reasons.

yum install tang nginx
#set tangd to run on port 8080
sed 's/ListenStream=80/ListenStream=8080/' /usr/lib/systemd/system/tangd.socket > /etc/systemd/system/tangd.socket
systemctl enable tangd.socket --now


location / {
proxy_pass http://localhost:8080;

To your nginx config, and start it. 

Check it's working with 'curl localhost/adv' and you should see some JSON back, starting {"payload": …}

But if you just want to test this, you'll need a spare drive or partition you can format:

cryptsetup luksFormat /dev/<partitionname> 
cryptsetup open /dev/<partitionname> test_new_part
mkfs -t xfs /dev/mapper/test_new_part

Wiping the drive is inherent in doing this - there's no other alternatives, you can't retrofit LUKS. 

Once you've got an encrypted partion, you can use clevis to 'bind' the partition:

clevis luks bind -d /dev/<partition> -f sss $CLEVIS_CFG

Note - I'm using just one tang host here, but for my 'real' config I'm using multiple, which is why I've got it set up with 'sss' to unlock - this lets me decrypt off any 1 (that's the 't' flag - you can make the number higher if you want) of the configured hosts.

This will prompt you for your LUKS password, and will add a 'key' into the LUKS config that you can now use to 'open' the device automatigically:

clevis luks unlock /dev/<partition> -n test_enc
mount /dev/mapper/test_enc /mnt/tmp

This is the process that dracut will do at boot, to decrypt. You can test/verify the clevis key with:

luksmeta show -d /dev/<partition> 

This will list you some 'active' slots - one of which will be your initial passphrase, and the other should be your clevis configuration.

[root@desktop-115 ~]# luksmeta show -d /dev/sdb1
0 active empty</p>
1 active cb6e8904-81ff-dead-beef-0123456feca334</p>
2 inactive empty
3 inactive empty
4 inactive empty
5 inactive empty
6 inactive empty
7 inactive empty

You can test this using luksmeta:

luksmeta load -d /dev/<partition> -s <slot> | clevis decrypt | cryptsetup luksOpen --test-passphrase /dev/<partition> <slot> && echo "Key is valid"

So now the tang/clevis combo is setup, the next trick is setting it to happen at boot. 

So kickstart is the tool for the job, because you don't want to go near cloning LUKS encrypted disks, because they'll share the encryption keys. 

My kickstart now has the line:

part pv.0 --size=100 --grow --asprimary --encrypted --passphrase=temp_password

Yes, I do use a 'bad' password (it's not _quite_ as bad as my example though - it's just the point is you have to assume it's too exposed to be 'safe') as part of the kickstart - that's deliberate, because it's changed later when I finish the install using ansible - it's quite hard to avoid exposing a password in kickstart. 

Included in 'packages' install of the kickstart:


And in the 'post' install section:

curl http://tang-0/adv -o /root/tang-0.jws
curl http://tang-1/adv -o /root/tang-1.jws
for device in /dev/sd*
  echo checking $device
  cryptsetup isLuks $device
  if [ $? == 0 ]
    echo "$device is LUKS doing clevis sss config"
    echo temp | clevis luks bind -k - -d $device -f sss $CLEVIS_CFG

Note - we fetch the 'adv' manually, because then the clevis bind doesn't prompt us to accept the host keys of the tang servers. This is functionally equivalent to trusting a ssh host key, so treat with due caution. 

And then - hopefully - once the kickstart is done, the client should move on past the 'encryption password' phase after a matter of seconds (can be 30 or so I find) and boot up automatically.

Once the boot is done, you should definitely then rewrite the LUKS 'dirty' password -:

echo -e "temp_password\nbetter_password" | cryptsetup luksChangeKey /dev/<partition>


Leave a comment