Starting systemd Services when Encrypted Device is plugged in

              ·

Problem: You want to start a service only once an encrypted harddrive is plugged in.

On our embedded iconnect box, we run an mpd whose music collection is stored on an external, encrypted hdd. The mpd should only start when the device is plugged in, since otherwise it would rescan its collection every time the hdd is not present. To achieve that, we can use systemd’s ability to define dependencies.
In general, it works like that:

Udev Rule

The hdd is connected via USB as /dev/sdb. We call it media which also corresponds to the filesystem label of the only partition. You can find out the devices’ serial number with

# udevadm info --path /sys/class/block/sdb1 | grep SERIAL_SHORT                             
E: ID_SERIAL_SHORT=222254634873

The resulting udev rule in /etc/udev/rules.d/45-media.rules looks like that:

ACTION=="add", KERNEL=="sd?1", SUBSYSTEMS=="usb", ATTRS{serial}=="222254634873", TAG+="systemd", ENV{SYSTEMD_WANTS}+="systemd-cryptsetup@media.service"

It matches the serial and triggers the execution of the systemd-cryptsetup@media.service unit

Cryptsetup

The unit for decryption is stored in /etc/systemd/system/systemd-cryptsetup@media.service.

[Unit]
Description=Cryptography Setup for %I
Documentation=man:systemd-cryptsetup@.service(8) man:crypttab(5)
SourcePath=/etc/crypttab
Conflicts=umount.target
DefaultDependencies=no
IgnoreOnIsolate=true
RequiresMountsFor=/root/.iconnect.key
BindsTo=dev-disk-by\x2duuid-6bf06a61\x2d16c7\x2d44c9\x2d98e0\x2d6ad295a19ab5.device
Wants=mnt-media.mount
Before=mnt-media.mount

[Service]
Type=oneshot
RemainAfterExit=yes
TimeoutSec=0
ExecStart=/usr/lib/systemd/systemd-cryptsetup attach 'media' '/dev/disk/by-uuid/6bf06a61-16c7-44c9-98e0-6ad295a19ab5' '/root/.iconnect.key' 'noauto'
ExecStop=/usr/lib/systemd/systemd-cryptsetup detach 'media'

Such a unit is automatically created by systemd out of /etc/crypttab during boot. Anyways, these cannot be used in our scenario, so we have to generate it manually. These are the steps I applied to create it

Mounting

The unit which is responsible for mounting the decrypted device node can be found in /etc/systemd/system/mnt-media.mount

[Unit]
Description = Media Disk
Before=mpd.service
Wants=mpd.service
Wants=systemd-cryptsetup@media.service
After=systemd-cryptsetup@media.service

[Mount]
What = /dev/disk/by-uuid/1f16ad25-7aa4-4064-a1b9-05f4f1cd246b
Where = /mnt/media
Type = ext4

The UUID is different from the first we saw. It is the one of the decrypted filesystem, obtained by ls -l /dev/disk/by-uuid | grep media. It will mount to /mnt/media. Note that you have to change the filename if your mount point is different.
As you can see, this unit will start mpd.service. It can also start another daemon if desired.

The main advantage of this approach is its flexibility when it comes to inter-process dependencies. The mpd itself may also depend on other services being started beforehead, such as pulseaudio. It seems rather complex, but the whole setup will guarantee, that mpd is only started when the hdd is plugged in. By giving pulseaudio as a dependency for mpd, it is also ensured, that sound output is set up properly and no user interaction is involved to listen to music.