I’m experimenting right now with different ways of creating secure Linux installations. Currently, the setup that I am trying to create is one where the root file system is stored on a LUKS-encrypted internal SSD, and the EFI System Partition (ESP) is stored on an external USB drive along with another LUKS volume, containing the root volume’s key file and detached LUKS header. I’m able to accomplish this with the following /etc/crypttab.initramfs and /etc/fstab.
# /etc/crypttab.initramfs
#
# <target> <source device> <key file> <options>
keys LABEL=cryptkeys none luks,tries=5,readonly
root LABEL=cryptroot /cryptroot.key:LABEL=keys luks,discard,header=/cryptroot.hdr:LABEL=keys
# /etc/fstab
#
# <file system> <mount point> <type> <options> <dump> <pass>
LABEL=root / ext4 defaults 0 1
LABEL=UEFI /boot/efi vfat defaults,nodev,noexec,nosuid,fmask=0177 0 2
LABEL=keys /keys ext4 defaults,nodev,noexec,nosuid,noauto 0 2
In the initramfs, the cryptkeys volume is unlocked and mounted to /keys, and then the cryptroot volume is successfully unlocked using the key file and detached LUKS header stored within the decrypted cryptkeys volume.
The problem that I’m running into is that the cryptkeys volume is NOT closed after the root volume is unlocked. The noauto option in /etc/fstab prevents it from being auto-mounted under the new system root, but the volume is still unlocked and mapped at /dev/mapper/keys, allowing an attacker with root privileges to simply mount the volume and read its contents, without having to know the password.
Ideally, I would like the cryptkeys volume to be unlocked for as short a period of time as possible, but, at the very least, it should NOT be unlocked outside of the initramfs. I’m using a systemd-based initramfs, and I read that, for such initramfs, you should use systemd services instead of initramfs hooks. I don’t know if that’s accurate or not, but I would like to follow best practices. That said, I’m not married to any one particular way of achieving my overarching goal, which is to ensure that the root volume’s key file and detached LUKS header remain encrypted outside the initramfs, but I would like to avoid solutions that are fragile or overly complex. For example, if it would be simpler to encrypt the key file and detached LUKS header with GPG or OpenSSL, instead of storing them in a separate LUKS volume, then that would be fine too.
Going with the systemd service approach, this is what I’ve come up with so far, but I’m currently running into a race condition that’s causing the service to fail sporadically, resulting in either the cryptkeys volume remaining unlocked after boot or the boot to fail entirely.
# /etc/systemd/system/initrd-cleanup-cryptkeys.service
[Unit]
Description=Unmount and Lock the cryptkeys LUKS volume
DefaultDependencies=no
AssertPathExists=/etc/initrd-release
ConditionPathExists=/dev/mapper/keys
OnFailure=emergency.target
OnFailureJobMode=replace-irreversibly
After=initrd-root-device.target
Before=initrd-root-fs.target
[Service]
Type=oneshot
ExecStart=/usr/bin/umount /dev/mapper/keys
ExecStart=/usr/lib/systemd/systemd-cryptsetup detach keys
I’ve tried various incantations of the above systemd service, but nothing has been consistently successful.
Specifically, I have …
- Tried with and without the
ExecStart=/usr/bin/umount /dev/mapper/keysline - Tried the following values for the
After=directivesystemd-cryptsetup@root.targetblockdev@dev-mapper-root.targetinitrd-root-device.targetinitrd-root-fs.targetinitrd.target
- Tried the following values for the
Before=directiveinitrd-root-fs.targetinitrd.targetinitrd-switch-root.target
For each attempt, I created a symlink at /etc/systemd/system/<before>.target.wants/initrd-cleanup-cryptkeys.service to /etc/systemd/system/initrd-cleanup-cryptkeys.service, replacing <before> with the value, specified in the Before= directive.
Can someone please tell me what I’m doing wrong here, or suggest a better way to accomplish what it is that I’m trying to do?