Full disk encryption in a Linux server environment is hard to do reliably. As a result, a lot of servers in Data Centers around the world are not encrypted. These days, that is quickly becoming an unacceptable practice. Red Hat recently took a stab at this one, and gave us Network Bound Disk Encryption(NBDE). Lets see if we can get it working.

I am using VMWare workstation with two CentOS8 machines. One will be my tang server, and the other will be my client already provisioned with full disk encryption. On the machine with full disk encryption, we will be running clevis. For clarification purposes, I will set the hostname of each box to their intended purpose (eg: tang, or clevis).

Setup Tang server.

Tang describes itself as a Network-Based Cryptographic Binding server. To be honest, all you have to know here is that tang is not just a stash of keys. In fact, the key to unlock your LUKS is not actually ever stored in tang.

Lets start by getting tang installed, configured, and started.

[root@tang ~]# dnf -y install tang
[root@tang ~]#
[root@tang ~]# systemctl enable tangd.socket
Created symlink /etc/systemd/system/ → /usr/lib/systemd/system/tangd.socket.
[root@tang ~]# systemctl start tangd.socket
[root@tang ~]# firewall-cmd --zone=public --add-port=80/tcp --permanent
[root@tang ~]# firewall-cmd --reload
[root@tang ~]#


Lets quickly note which keys we are advertising:

[root@tang tang]# tang-show-keys
[root@tang tang]#

When we later bind our clevis server to this tang server. We should see this key.

Setup Clevis client

This is our client, who is already encrypted using LUKS.

[root@clevis ~]# lsblk
NAME                                          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sr0                                            11:0    1  597M  0 rom
nvme0n1                                       259:0    0   20G  0 disk
├nvme0n1p1                                   259:1    0    1G  0 part  /boot
└nvme0n1p2                                   259:2    0   19G  0 part
  └luks-2833c165-f360-479c-ad56-1516508cc3fe 253:0    0   19G  0 crypt
    ├cl_bdeclient-root                      253:1    0   17G  0 lvm   /
    └cl_bdeclient-swap                      253:2    0    2G  0 lvm   [SWAP]
[root@clevis ~]#


As you can see, our target partition is nvme0n1p2. Lets dig a bit more.

[root@clevis ~]# cryptsetup luksDump /dev/nvme0n1p2
LUKS header information for /dev/nvme0n1p2

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        512
MK digest:      e5 94 85 04 86 29 61 77 2d a4 6e 2a be 97 cb 49 a7 8b 49 06
MK salt:        70 d0 cf 2e 07 d5 00 d5 9c 24 5b c2 49 1c 21 77
                32 66 f4 e3 7a c5 52 a7 a8 b2 80 15 9c 00 16 23
MK iterations:  120470
UUID:           2833c165-f360-479c-ad56-1516508cc3fe

Key Slot 0: ENABLED
        Iterations:             1971006
        Salt:                   3a 94 28 21 fe 65 00 87 09 fd b4 00 e9 48 fb a7
                                17 5a ee 02 1b 37 cb 53 52 aa 22 21 3c a4 21 c5
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED
[root@clevis ~]#

Notice how key slot 0 is in use. That is the slot using the password. We want to take the advertised key from the tang server and shove it in a slot. For handling this, we will use Clevis. Note, in a pinch you can query your tang server using curl, and grab this key the tang server is advertising (curl http://$tang_server/adv). But we dont need that, since our clevis bind command will do it.

Install Clevis

[root@clevis ~]# yum -y install clevis clevis-luks clevis-dracut
[root@clevis ~]#

With Clevis installed, we now bind to our tang server.

[root@clevis ~]# clevis luks bind -d /dev/nvme0n1p2 tang '{"url":""}'
The advertisement contains the following signing keys:


Do you wish to trust these keys? [ynYN] y
Enter existing LUKS password:
[root@clevis ~]# luksmeta show -d /dev/nvme0n1p2
0   active empty
1   active cb6e8904-81ff-40da-a84a-07ab9ab5715e
2 inactive empty
3 inactive empty
4 inactive empty
5 inactive empty
6 inactive empty
7 inactive empty
[root@clevis ~]# dracut -fv --regenerate-all

We accepted the signing key we saw when we setup our tang server. Then we entered our LUKS password. Now slot 1 is populated..  

If your environment uses DHCP, then you just need to run dracut -fv --regenerate-all to regenerate the initrd.
If you have a static IP, you have two options. either you can pass it to dracut using –kernel-cmdline or you can add a config file to /etc/dracut.conf.d/whatever.conf. Using a config file will survive kernel updates. So lets use that method.

echo 'kernel_cmdline="ip=" ' > /etc/dracut.conf.d/whatever.conf
dracut -fv --regenerate-all

Obviously you should update the fields with your network configuration. But you have to make sure you update this config file, and re-run dracut every time you change your IP.
The reason this is necessary, is because your root file system is encrypted. The kernel has to be able to communicate with the tang server, so it needs to be able to handle networking on its own.

Conclusion / Demo.

There was no reasonable way for me to show this. So I went ahead and recorded it, and then converted it to a gif.

nbde demo

I start by showing the tangd.socket status, and then restarting the nbde client. We then see the client automatically decrypt.

Lastly, the log from the tang server

May 12 18:34:42 tang systemd[1]: Started Tang Server (
May 12 18:34:42 tang tangd[3644]: GET /adv/ => 200 (src/tangd.c:85)
May 12 18:36:09 tang systemd[1]: Started Tang Server (
May 12 18:36:09 tang tangd[3650]: GET /adv/ => 200 (src/tangd.c:85)
May 12 18:40:14 tang systemd[1]: Started Tang Server (
May 12 18:40:14 tang tangd[3654]: POST /rec/77R7FPnNptBFtnBEeF2Oe-D3P44 => 200 (src/tangd.c:168)


Extra - Delete the tang server association

If for some reason, you are not happy with it, you can remove a key from one of the slots by doing the following:

[root@clevis ~]# luksmeta wipe -d /dev/nvme0n1p2 -s 1
You are about to wipe a slot. This operation is unrecoverable.
A backup is advised before proceeding.

Do you wish to erase slot 1 on /dev/nvme0n1p2? [yn] y
[root@clevis ~]# dracut -f --regenerate-all
[root@clevis ~]# luksmeta show -d /dev/nvme0n1p2
0   active empty
1 inactive empty
2 inactive empty
3 inactive empty
4 inactive empty
5 inactive empty
6 inactive empty
7 inactive empty

To be clear, you should not do this unless you want to REMOVE the key from the LUKS slot. In other words, you will need your original password to decrypt the disk.