Unlock encrypted partitions with Tang

In this article I describe how to set up a Tang server on a Fedora 29 Server Edition Linux and how to use it to unlock encrypted volumes of a Fedora 29 Workstation Edition Linux during the early boot phase.

Disclaimer

The author is not to be held responsible for any damage caused by following these instructions.

Warning

This manual deals with device encryption of computers. Errors can lead to data loss. Users who are not familiar with this topic are advised not to make these changes themselves.
You are advised to study the linked Red Hat Documentation which is providing a lot more information on the topic and also security considerations!

Server: Installing Tang Service

To install Tang Service run this command:

sudo dnf install tang

Tang is installed preconfigured port 80/tcp. That port is usually blocked by a web server like apache. Also in other ports it failed to load in my test. I therefore checked selinux and found out, that in Fedora 29 tangd is expected to use port 7406/tcp (cf. Github). Look at this file:

cat /etc/systemd/system/multi-user.target.wants/tangd.socket 
[Unit]
Description=Tang Server socket
Requires=tangd-keygen.service
Requires=tangd-update.service
Requires=tangd-update.path
After=tangd-keygen.service
After=tangd-update.service
After=NetworkManager.service

[Socket]
ListenStream=80
Accept=true

[Install]
WantedBy=multi-user.target

To change the port to 7406 type

systemctl edit tangd.socket

and paste the following:

[Socket]
ListenStream=
ListenStream=740

Save and exit. After this, reload the systemd units, enable and start Tang with these commands:

systemctl daemon-reload
systemctl enable tangd.socket
systemctl start tangd.socket

Now open the port on the firewall of your server. To make a permanent role run the following command. Note that your “zones” might be different, of you are not using Fedora 29 server edition.

firewall-cmd --zone=FedoraServer --add-port=7406/tcp --permanent

Finally you have to create keys for your Tang server. These will later be used by clients to unlock their encrypted drives or volumes.

DB=/var/db/tang
jose jwk gen -i '{"alg":"ES512"}' -o $DB/new_sig.jwk
jose jwk gen -i '{"alg":"ECMR"}' -o $DB/new_exc.jwk

Client: Unlock encrypted volumes with Tang

On your client computer you need the “clevis” tools to unlock your encrypted drives and volumes. To do this during early boot phase you also need to modify dracut and write a customized initramfs which includes network drivers and a network manager.

This has been tested on a Fedora Linux 29. The procedure might be different if you use another distribution or version.

Note: Clevis seems only to support LUKSv1 encryption. Fedora Linux 30+ by default uses LUKSv2 during the setup process.

Install clevis:

dnf install clevis-luks clevis-dracut clevis

Next you configure the volumes which are to be unlocked by clevis at early boot stage. If you are not sure how your partitions are configured, start “blivet-gui”. The following example shows the default configuration in Fedora if the encryption option was selected during installation.

In the example shown above the encrypted logical volume is called “fedora”. Its device name can be deduced to be /dev/sda3. Try this command to show some information about the cryptographic setup of that partition:

sudo cryptsetup luksDump /dev/sda3

What we will do next is to bind another master key to the LUKS volume. This master key is loaded at early boot stage from the Tang server.

sudo clevis luks bind -d /dev/sda3 tang '{"url":"http://server_ip:7406"}

When this is done, check if a new token has been written to the LUKS volume.

For LUKS v1:

luksmeta show -d /dev/sda3
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

For LUKS v2:

sudo cryptsetup luksDump /dev/sda3
Tokens:
  0: clevis
    Keyslot:  1

Because of a bug in luksmeta, the token might be written to an inactive slot. If this is the case for you then please repeat the binding process.

The next step is to create a new initramfs with dracut. Dracut is modular and functions can be integrated. As an addition to the modules already in your initramfs you are about to add networking functionality and the driver module for your network card.

To find out which kernel module is currently loaded for your ethernet card, run lspci:

lspci -k

00:19.0 Ethernet controller: Intel Corporation Ethernet Connection I217-V (rev 04)
	DeviceName:  Onboard LAN
	Subsystem: Lenovo Device 309e
	Kernel driver in use: e1000e
	Kernel modules: e1000e

In this example it is the “e1000e” kernel module. We will add this to the dracut configuration file together with the networking modules of dracut. To do this edit the /etc/dracut.conf file:

sudo vim /etc/dracut.conf

# PUT YOUR CONFIG IN separate files
# in /etc/dracut.conf.d named "<name>.conf"
# SEE man dracut.conf(5) for options
add_dracutmodules="network"
add_drivers="e1000e"

Add the listed two lines. After this you need to rebuild the initramfs:

sudo dracut -f

And here comes a possible problem. A standard /boot partition in Fedora is (only) 200 MB big. That is barely enough to hold 3 kernels and 3 initramfs modules.

Type in this command to check how much space is available on your /boot partition:

df -h /boot

With Fedora 29 dracut will throw an error here, that part of a network module is missing. Ignore the bug, its already reported. The setup will work nevertheless.

If its already full (at 5% or less available), you could run into problems with the next kernel update, because due to the new modules, your initramfs files will grow by some Megabytes. The next kernel update may not fit in here anymore.

Usually Fedora keeps two additional older kernels as a fallback system. If you add a lot of functionality to the early boot stage, the initramfs files will grow. Therefore you need to reduce the amount of kernels in /boot to two (current + 1 old).

Uninstall the older kernel module with this command:

sudo dnf remove $(dnf repoquery --installonly --latest-limit=-2 -q)

And change the DNF configuration accordingly:

sudo vim /etc/dnf/dnf.conf

[main]
gpgcheck=1
installonly_limit=2
clean_requirements_on_remove=True

Your /boot volume should now look like this:

ls -alh /boot

 160M
dr-xr-xr-x.  7 root root 4,0K 16. Feb 01:32 .
dr-xr-xr-x. 18 root root 4,0K 16. Feb 01:18 ..
-rw-r--r--.  1 root root 197K 31. Jan 17:11 config-4.20.6-200.fc29.x86_64
-rw-r--r--.  1 root root 197K  6. Feb 20:37 config-4.20.7-200.fc29.x86_64
drwx------.  4 root root  16K  1. Jan 1970  efi
-rw-r--r--.  1 root root 185K  5. Feb 15:50 elf-memtest86+-5.01
drwxr-xr-x.  2 root root 4,0K 25. Okt 01:59 extlinux
drwx------.  3 root root 4,0K 25. Nov 18:45 grub2
-rw-------.  1 root root  68M 25. Nov 18:45 initramfs-0-rescue-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.img
-rw-------.  1 root root  30M 16. Feb 00:53 initramfs-4.20.6-200.fc29.x86_64.img
-rw-------.  1 root root  30M 16. Feb 12:23 initramfs-4.20.7-200.fc29.x86_64.img
drwxr-xr-x.  3 root root 4,0K 25. Okt 02:01 loader
drwx------.  2 root root  16K 25. Nov 18:41 lost+found
-rw-r--r--.  1 root root 183K  5. Feb 15:50 memtest86+-5.01
-rw-------.  1 root root 4,0M 31. Jan 17:11 System.map-4.20.6-200.fc29.x86_64
-rw-------.  1 root root 4,0M  6. Feb 20:37 System.map-4.20.7-200.fc29.x86_64
-rwxr-xr-x.  1 root root 8,3M 25. Nov 18:45 vmlinuz-0-rescue-192be126ef6348f28a0a35ee709cd9c5
-rwxr-xr-x.  1 root root 8,4M 31. Jan 17:12 vmlinuz-4.20.6-200.fc29.x86_64
-rw-r--r--.  1 root root  167 31. Jan 17:07 .vmlinuz-4.20.6-200.fc29.x86_64.hmac
-rwxr-xr-x.  1 root root 8,4M  6. Feb 20:37 vmlinuz-4.20.7-200.fc29.x86_64
-rw-r--r--.  1 root root  167  6. Feb 20:32 .vmlinuz-4.20.7-200.fc29.x86_64.hmac

Finally you have to add some boot parameters: Edit your GRUB default config file and add “rd.neednet=1 ip=dhcp” in the line GRUB_CMDLINE_LINUX

sudo vim /etc/default/grub
GRUB_CMDLINE_LINUX="... rhgb quiet rd.neednet=1 ip=dhcp"

Install grub (to EFI) with this command:

sudo grub2-mkconfig --output /etc/grub2-efi.cfg 

Now reboot your system to see if everything works.

If you are running into a black screen, press ESC on your keyboard to see what’s going in.

  • It may take some seconds before clevis kicks in and unlocks your volume. The password prompt will be shown during that time.
  • If your system crashes (no response to ESC) on a black screen, then restart the PC and select the older kernel. You may have to press up – down – up – down – on your keyboard to get into grub. When you are back in your system run this command to completely rebuild the initramfs:
sudo dracut --regenerate-all --force

Further reading

  • The Red Hat documentation on this topic: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-policy-based_decryption
  • My article about TPM based unlocking: https://techrevelations.de/2019/02/04/tpm-encryption-in-fedora-linux/
Leave a Reply

Your email address will not be published. Required fields are marked *