Sometimes it is necessary that the system disk is encrypted and the system is loaded automatically. In this short outline i will focus on how to make it work.

I will use the key file on the USB storage device. You must consider the risks of using such configuration.

Create key:

dd if=/dev/random of=secretkey bs=1 count=4096

Add the key to your LUKS volume:

cryptsetup luksAddKey /dev/your_luks_dev secretkey

Copy the key to your usb storage (it is ext3 filesystem and labeled ‘USBCRYPT’ in my case).

mount /dev/disk/by-label/USBCRYPT /mnt
cp secretkey /mnt/
umount /mnt

Edit volume record in /etc/crypttab:

Before:

root_volume_crypt UUID=714e7ed2-af19-4214-8981-34ba71652bf7 none luks

After:

root_volume_crypt UUID=714e7ed2-af19-4214-8981-34ba71652bf7 /dev/disk/by-label/USBCRYPT:/secretkey luks,keyscript=/lib/cryptsetup/scripts/passdev

Check whether the file /lib/cryptsetup/scripts/passdev exists in your setup.

If you have other partitions that you want to mount after boot, the records for them will look like this:

another_volume_crypt UUID=11f68a35-9fac-4f2b-81d2-593f739c8273 /path/to/anothersecretkey luks

Do not forget to configure mounts in /etc/fstab:

/dev/mapper/root_volume_crypt / ext4 errors=remount-ro,nodelalloc,data=ordered 0 1
/dev/mapper/another_volume_crypt /your/mountpoint ext4 defaults,nodelalloc,data=ordered,user,users,nodev 0 2

After that I got some problems using this configuration because of one volume was mounted by passdev script and the others by systemd.

Systemd waited for the already mounted drive 90 seconds during boot. This timer could not be disabled because the systemd automatically generated the service from the template using systemd-cryptsetup-generator.

I did not find any simple and beautiful way to solve it and I had to make a patch.

This is it:

diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 2d00bcf..0ca9c4b 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -384,6 +384,7 @@ static int add_crypttab_devices(void) {
                 char line[LINE_MAX], *l, *uuid;
                 crypto_device *d = NULL;
                 _cleanup_free_ char *name = NULL, *device = NULL, *keyfile = NULL, *options = NULL;
+                bool keyscript;
 
                 if (!fgets(line, sizeof(line), f))
                         break;
@@ -413,6 +414,12 @@ static int add_crypttab_devices(void) {
                         continue;
                 }
 
+                keyscript = fstab_test_option(options, "keyscript\0");
+                if (keyscript) {
+                        log_info("Not creating device '%s' because it has keyscript option.", name);
+                        continue;
+                }
+
                 r = create_disk(name, device, keyfile, (d && d->options) ? d->options : options);
                 if (r < 0)
                         return r;

I used Docker for compiling and building systemd debian package.

Dockerfile:

FROM debian:9

RUN echo "deb-src http://ftp.ru.debian.org/debian/ stretch main non-free contrib" >> /etc/apt/sources.list && \
    apt update && \
    apt install -y dpkg-dev devscripts && \
    apt build-dep -y systemd

RUN apt install -y nano

RUN useradd -m builder

WORKDIR /home/builder
USER builder
ENTRYPOINT [ "bash" ]

Systemd docker image build command:

docker build -t systemd .

Systemd docker container run command:

docker run -it --rm --name systemd -v $(pwd)/data:/home/builder -v $(pwd)/patch:/patch systemd

Systemd package build command sequence:

apt source systemd
cd systemd-*
git apply /patch
dpkg-source --commit
debuild -us -uc

You will get several .deb packages. systemd-cryptsetup-generator is in systemd_232-*.deb.