Mount a LUKS partition with a password-protected GPG-encrypted key using systemd

I recently took a good resolution for my laptop: increase the security of some sensitive data using LUKS. Because I'm using a password-protected gpg-encrypted key, I can't use any automatic mount tool like dracut or automount so I use a bunch of systemd service files.

Note: I'm using the user part of systemd, but this article is not about its configuration.


The first tool I need is gpg-agent which is not system-wide, so I create an unit file named gpg-agent.service:

Description=GPG Agent Daemon

ExecStart=/usr/bin/gpg-agent --daemon --no-detach
ExecReload=/bin/kill -HUP $MAINPID


If you need the SSH Agent support, append --enable-ssh-support to ExecStart.
ExecReload is used to clean the passphrases cache when you want (reload gpg-agent with: systemctl --user reload gpg-agent.service).

Note: Don't forget to append use-agent in ~/.gnupg/gpg.conf and customize the agent configuration with ~/.gnupg/gpg-agent.conf


I've found a script for mounting a LUKS partition with automount. I've customized it for my own use:



# The cryptsetup tool from the package of the same name

# This is the raw device that we will mount

# This is the encryption key file, encrypted using gpg

# Mount options for the encrypted fileystem
mount_opts="-t ext4 -o defaults,noatime,nodiratime,users,owner,exec"

# The mapped block device

# Give up if there is no key or setup tool
# [ -r $key_file ] || exit 0
[ -x $CRYPTSETUP ] || exit 1

# If there is an encrypted device mapped in already, it must be from a
# previous mount. It may be out-of-date so remove it now.
[ -b $crypt_device ] && sudo $CRYPTSETUP remove $key

# Give up if the raw device doesn't have a LUKS header
sudo $CRYPTSETUP isLuks $mount_device || exit 2

# Open the encrypted block device
gpg --batch --decrypt $key_file 2>/dev/null | sudo $CRYPTSETUP -d - luksOpen $mount_device $key >& /dev/null || exit 3

# If we ended up with a block device, mount it
if [ -b $crypt_device ]; then
  sudo mount $mount_opts /dev/mapper/$key {mountpath}
exit 0

{keyname}: Name of the LUKS device
{device}: LUKS disk device
{keypath}: absolute path of the gpg-encrypted key to unlock the LUKS device
{mountpath}: absolute path of the mount point

Note: I'm using sudo to be able to call cryptsetup and mount with root privileges (without password).

Now with this script, we can make a new unit file for LUKS named luks.service:

Description=Mount LUKS



Mount LUKS as a requirement for X

This section is optional. Some of important files for the boot of my X session are on the LUKS partition so I need to mount it before X starts.

I don't use any login manager (like gdm or lightdm) and I start X after the tty login. To make sure everything is set up, I do it via another unit file named xsession.service:

Description=XSession Service
Requires=gpg-agent.service luks.service



Note: I specify xsession to only start after luks.service and it explicitely requires gpg-agent.service for future use

Now, I execute systemctl --user start xsession.service and it will start GPG Agent and the LUKS mount script for me (and X, of course).

Enjoy it!