It took me about 6 hours to find out all of this, but after reading a ton of man pages, initram scripts, and bug reports, I got a working result that takes about 2' to set up...
The point is to have a SWAP partition encrypted with LUKS, and it should be decypted during boot.
When using SysV, initram hooks and scripts in Debian worked like a charm but then, Systemd came and it's not yet fully implemented so this kind of crap happens. Systemd's cryptsetup doesn't support parameters in /etc/crypttab
so using a script there is ignored:
/* Options Debian's crypttab knows we don't:
precheck=
check=
checkargs=
noearly=
loud=
keyscript=
*/
Trying to decrypt SWAP partition via /etc/crypttab
ends up usable but it can't resume from hibernation because Systemd tries to open it way too late, so the kernel gives up looking for a SWAP. To make it work, you need to pass parameters to the kernel, which Systemd will elegantly take.
Here's the whole deal (read everything first before starting doing things):
Let's say that your encrypted root partition is at /dev/disk/by-partlabel/root
and your SWAP, /dev/disk/by-partlabel/swap
(here I used GPT partition labels, you can also use UUID). I'll be naming cryptoroot
and cryptoswap
to the opened devices (accesible via /dev/mapper/...
).
1- Edit or create /etc/initramfs-tools/conf.d/resume
:
RESUME=/dev/mapper/cryptoswap
2- Remove references to SWAP in /etc/crypttab
, i.e. a line like cryptoswap /dev/disk... /dev/urandom swap
must be commented out or deleted.
3- Edit /etc/default/grub
to set the kernel parameters for resume device and encryption:
GRUB_CMDLINE_LINUX="resume=/dev/mapper/cryptoswap cryptopts=source=/dev/disk/by-partlabel/root,target=cryptoroot cryptopts=source=/dev/disk/by-partlabel/swap,target=cryptoswap"
4- Update initramfs and grub: sudo update-initramfs -u && sudo update-grub
Up to this point, you will need a password to open both devices, which is horribly anoying. However, a neat script, provided by cryptsetup, can be used: decypt_derived
, which derives a key from an opened device (say, the root device). So, here's what you need to do (skip previous 3rd and 4th steps):
3- Add derived key to SWAP: sudo cryptsetup luksAddKey /dev/disk/by-partlabel/swap <(/lib/cryptsetup/scripts/decrypt_derived cryptoroot)
Verify that it worked: cryptsetup -v --test-passphrase -d <(/lib/cryptsetup/scripts/decrypt_derived cryptoroot) luksOpen /dev/disk/by-partlabel/swap
4- Edit /etc/default/grub
:
GRUB_CMDLINE_LINUX="resume=/dev/mapper/cryptoswap cryptopts=source=/dev/disk/by-partlabel/root,target=cryptoroot cryptopts=source=/dev/disk/by-partlabel/swap,target=cryptoswap,keyscript=/lib/cryptsetup/scripts/decrypt_derived,key=cryptoroot"
Double-check device and partition names!
5- Add an initram hook to copy decypt_derived binary to the initramfs, create the file /etc/initramfs-tools/hooks/cp_decrypt_derived
:
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
# Begin real processing below this line
copy_exec /lib/cryptsetup/scripts/decrypt_derived /lib/cryptsetup/scripts/ >&2
6- Update initramfs and grub: sudo update-initramfs -u && sudo update-grub
That's it! You can hibernate with systemctl hibernate
(no need for sudo). If you use a keyfile for the root partition, the same can be done by pointing the kernel to an appropriate keyscript that reads and pushes the key, and a hook that copies said script into initramfs.
Sources
- https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1451032
- https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=618862
- https://news.ycombinator.com/item?id=8477913
- http://manpages.ubuntu.com/manpages/zesty/man8/initramfs-tools.8.html
- https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=475838
- http://www.matthew.ath.cx/articles/cryptkey
Hi, thanks for this information.
This is still relevant for Buster (v10, stable) but I found a couple of modifications were needed for the cryptopts command, in order for a smooth and error/warning free boot. Namely:
hash=
andcipher=
- the relevant values being obtained from acryptseup luksDump /dev/sdX
e.g. the line might become: