Stop Driving Home to Unlock Your Server: Automatic Disk Decryption with Tang and Clevis
Have you ever set up disk encryption on your Linux server and had to unlock it by putting in the passphrase?
Have you ever had the server reboot for some reason when you’re incredibly far away?
Then you have to drive all the way back home or get someone to type in your passphrase just to get your server working again?
This exact scenario happened to me after I rebooted my server after critical updates.
Thankfully we can use Clevis and Tang to decrypt the drive automatically.
WHAT IS CLEVIS AND TANG?
What is Clevis?
It’s a framework for automated decryption. It lets you add additional ways to unlock a LUKS volume besides typing a passphrase.
What is Tang?
Tang is a server that Clevis (client) talks to at boot, as long as it’s reachable over the network.
This means that your machine can be decrypted automatically as long as it’s on the correct network.
HOW DOES IT DECRYPT THE DRIVE?
Tang and Clevis use asymmetrical encryption referred to as the McCallum-Relyea key exchange protocol.
1. Tang (server) publishes its public key.
2. Clevis (Client) generates a random disk unlock secret.
3. Clevis uses Tang’s public key to encrypt the secret and stores the encrypted data in LUKS.
4. At boot, Clevis sends Tang the stored key-exchange data that was created when the disk was enrolled.
5. Tang uses its private key to perform a mathematical operation that only Tang can perform and returns the result to Clevis.
6. Clevis combines that result with its locally stored data to reconstruct the unlock secret and unlock the disk.
INSTALL TANG
On a separate machine we will install Tang:
sudo apt install tang -yStart and enable the tang socket:
sudo systemctl enable --now tangd.socketThe difference between a service and a socket is that a service is a background program that performs task, whereas a socket is a communication endpoint used by programs to send and receive data.
If you get an error about a port conflict, then add in this override to change the port. In the below example we set it to 7500:
sudo mkdir -p /etc/systemd/system/tangd.socket.dsudo tee /etc/systemd/system/tangd.socket.d/override.conf <<'EOF'
[Socket]
ListenStream=
ListenStream=7500
EOF- The first
ListenStream=clears the default port - The second
ListenStream=7500sets the port to be 7500
Restart the socket:
sudo systemctl restart tangd.socketVerify that it’s listening:
sudo systemctl status tangd.socket && sudo ss -tlnp | grep 7500OPTIONAL — Restrict firewall access (below example uses firewalld):
sudo firewall-cmd --permanent --zone=FedoraServer --add-rich-rule='rule family="ipv4" source address="<encrypted-host-IP>" port port="7500" protocol="tcp" accept'
sudo firewall-cmd --reloadThat is all the configuration that’s needed for the Tang server.
FIND THE DRIVE THAT NEEDS TO BE DECRYPTED
Now we should switch over the the client, the device that needs to be unlocked every time it turns back on.
We have to find what is called ‘The LUKS partition’.
Get Lumenyx’s stories in your inbox
Join Medium for free to get updates from this writer.
This is what requires the decryption key upon boot.
A LUKS partition is a section of a storage drive encrypted using Linux Unified Key Setup to protect your files, system data, and personal information from unauthorized access.
We can find out which drive is our LUKS partition by utilising these commands:
lsblk -fsudo blkidFor me, it’s /dev/sda3.
BIND THE LUKS VOLUME TO TANG
First we have to install Clevis.
sudo dnf install clevis clevis-luks clevis-dracut -yWhat is ‘binding’?
‘Binding’ is the act of registering one of the automated unlock methods (like Tang) with your LUKS volume.
LUKS lets a disk have several valid unlock codes at once (referred to as keyslots), and binding adds an extra keyslot whose key can only be reconstructed by talking to Tang.
Bind the volume to your Tang server:
sudo clevis luks bind -d /dev/[VOLUME] tang '{"url":"http://<TANG-IPADDRESS>:[PORT]"}'Example:
sudo clevis luks bind -d /dev/sda3 tang '{"url":"http://192.168.0.14:7500"}'If the binding was successful, you should see see something like:
1: tang '{"url":"http://<pi-IP>:7500"}'
If it was unsuccessful you would receive an error like this:
You’ll be prompted for your existing LUKS passphrase to authorize the new binding, and asked to confirm trust of the Tang server’s advertisement.
REBUILD INITRAMFS
The initramfs is a temporary filesystem image used to help the Linux Kernel mount the root filesystem and run the main Init system.
Rebuild initramfs so that it includes Clevis, Tang, and networking support:
sudo dracut -f --regenerate-allDracut is a tool that’s used to build an initramfs image by reading your system configuration and copying only the necessary kernel modules/scripts/binaries into the emergency boot environment.
Since we installed
clevis-dracutearlier, it dropped the necessary files into/usr/lib/dracut/modules.d/.When dracut rebuilds the image, it also scans your system’s LUKS environment (via
/etc/crypttaband the LUKS headers) and notices that we already have a Tang/Clevis binding, therefore it will automatically add the Clevis module, as well as networking support since that is what Clevis depends on.
Now we have to verify that the rebuild actually pulled the correct components:
sudo lsinitrd /boot/initramfs-$(uname -r).img | grep -iE 'clevis|tang|NetworkManager'lsinitrd is a tool that’s used to show the contents of an initramfs image.
You should see clevis-decrypt-tang, clevis-luks-askpass, and NetworkManager binaries listed:
Add the required boot parameters:
sudo grubby --update-kernel=ALL --args="rd.neednet=1 rd.net.timeout.dhcp=30"This tells the boot sequence that we need networking as early as the boot-up process.
grubby is a command line tool for configuring grub and zipl.
Rebuild initramfs again:
sudo dracut -f --regenerate-allConfirm that the bootloader changes are present:
sudo bash -c "grep -o 'rd.neednet=1' /boot/loader/entries/*.conf"sudo bash -c "grep -o 'rd.net.timeout.dhcp=[0–9]*' /boot/loader/entries/*.conf"TESTING
Reboot the client and confirm if it unlocks automatically:
sudo rebootOn the server you can check the logs to see if Tang was contacted for the decryption (look for a POST /rec/... request, not just GET /adv):
sudo journalctl -u tangd.socket -u 'tangd@*' -fIf it unlocks with no prompt and you see that POST /rec/... line in the Pi's journal, then you have succeeded in having it unlock automatically.









