In the last few posts I’ve shown how to make a USB key for use as an encrypted gateway to unlocking and booting a Linux system. While the setup works, there are a few steps left that could be automated. Wouldn’t it be nice to have everything set up to just update itself without manual intervention on every kernel update?

Well, we’re not going to get quite that far - but very close. In fact, all that really remains is to ensure that /boot is mounted before upgrading the linux package and to rename the kernel and initramfs image files after the linux package builds them. This post will show how to do this, and also present an AUR package which will do the heavy lifting for Arch users.

fstab

First of all, you should already have /boot set up in your /etc/fstab. If not, do it now. Refer to the fstab Arch Wiki article if you need help with this.

Pacman hooks

If you’re not using Arch Linux, this section may not be of much help to you. Your package manager may provide functionality similar to the hook system used here, but you’re on your own figuring that out.

pacman [recently][pacman-hooks-release] released a hook API we can use to do the tedious things for us:

  1. Unlock and mount /boot before linux package upgrades
  2. Rename kernel and initramfs image files after linux package upgrade
  3. Unmount and close /boot

These are all really simple. All we need to do is place some files in /usr/share/libalpm/hooks/.

  • /usr/share/libalpm/hooks/shared-cryptboot-mount.hook:

    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = File
    Target = boot/*
    
    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = Package
    Target = linux
    
    [Action]
    Description = Mounting /boot ...
    When = PreTransaction
    Exec = /usr/bin/mount /boot
    AbortOnFail
  • /usr/share/libalpm/hooks/shared-cryptboot-unmount.hook:

    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = File
    Target = boot/*
    
    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = Package
    Target = linux
    
    [Action]
    Description = Unmounting /boot ...
    When = PostTransaction
    Exec = /usr/bin/umount /boot
  • /usr/share/libalpm/hooks/shared-cryptboot-build.hook:

    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = Package
    Target = linux
    
    [Action]
    Description = Rebuilding boot files on shared boot device...
    When = PostTransaction
    Exec = /usr/share/libalpm/scripts/shared-cryptboot-build
  • /usr/share/libalpm/scripts/shared-cryptboot-build:

    #!/bin/bash
    
    SHARED_CRYPTBOOT_IMAGE_SUFFIX=${SHARED_CRYPTBOOT_IMAGE_SUFFIX:-$(hostname)}
    
    cp /boot/vmlinuz-linux /boot/vmlinuz-linux-${SHARED_CRYPTBOOT_IMAGE_SUFFIX}
    cp /boot/initramfs-linux.img /boot/initramfs-linux-${SHARED_CRYPTBOOT_IMAGE_SUFFIX}.img

    Also remember to chmod a+x /usr/share/libalpm/scripts/shared-cryptboot-build, or pacman won't be able to run it. This hook copies the kernel and initramfs image files to file names with the hostname as a suffix - i.e. /boot/vmlinuz-linux-hugin on the hugin host. If you want another file name, just modify the hook and set SHARED_CRYPTBOOT_IMAGE_SUFFIX to something else - or replace the filename entirely if you prefer something completely different.

With this set up, pacman will attempt to mount /boot before upgrading the linux package. If it fails - for example, if you haven’t unlocked the encrypted container - it will abort the transaction and let you fix that. After upgrading the linux package, it will copy the new kernel and initramfs images to the safe file names used by GRUB as set up in the previous post. The only manual step remaining is to unlock and close the encrypted container - but I, at least, actually prefer to keep it that way.

Pacman hooks AUR package

If you’re like me, you don’t like having anything outside /home and /etc that’s not managed by the package manager. So I’ve packaged the above pacman hooks as the shared-cryptboot-utils package available in the AUR. Feel free to use it, and also to contribute any improvements you can think of!

Conclusion

These last three posts detail how I’ve set up a USB storage drive for use as a USB key in the true sense of the word, holding boot files and encryption headers for several different Linux systems - including one installed on the drive itself - and thus requiring a kind of 2-factor authentication for accessing these systems. I hope this will help you set up your own convoluted encryption rig - let me know what cool things you do with this, and what improvements you’ve thought of!