dracut
dracut copied to clipboard
[crypt] Detached LUKS header causes erroneous `/etc/block_uuid.map`
Describe the bug
Any LUKS encrypted device with detached header causes blkid $_dev -s UUID -o value to return nil here in modules.d/90crypt/module-setup.sh.
This results in an erroneous /etc/block_uuid.map being written to the initramfs, which greatly inhibits successful bootup of systems having detached headers on the LUKS root volume. A Dracut rescue shell is spawned.
Distribution used
Void Linux
Dracut version
053
Init system
runit
To Reproduce
In Void Linux live environment:
git clone https://github.com/atweiden/voidvault
cd voidvault
export RAKULIB="$(realpath lib)"
export RAKUDO_HOME=/usr/lib/raku
export PATH="$(realpath bin):$PATH"
# bootstrap void
voidvault new 1fa
Reboot after running script to completion.
Expected behavior
This issue calls into question the validity of /etc/block_uuid.map as an approach. While /etc/block_uuid.map could be made to include something here, rather than useless trailing whitespace, what would work? No UUID is possible to obtain.
Additional context
Unrelated to https://github.com/dracutdevs/dracut/issues/1566 — omitting rd.luks.name doesn’t rectify bootup errors.
Is there any solution how to use LUKS detached header for root using dracut?
@atweiden Your problem is using UUID instead of PARTUUID. With a detached header, you should be using the partition's UUID since there can be no filesystem UUID.
@reagentoo As of 5 minutes ago, there is now :) I just submitted a pull request, but until that processes through the system, see https://github.com/SentToDevNull/dracut for the dracut you should use. I store my detached header (e.g. "definitely_not_a_luks_header.img") on a separate disk (e.g. /dev/vda1) and use the following dracut cmdline options in my GRUB config:
menuentry "Gentoo" {
linux /vmlinuz-superkernel \
rd.luks.partuuid=3c9d04af-02 \
rd.luks.header=definitely_not_a_luks_header.img \
rd.luks.header.disk=/dev/vda1 \
root=/dev/mapper/luks-3c9d04af-02 \
rw \
quiet
initrd /initramfs-superkernel.img
}
Reminder: use PARTUUID with detached headers because they don't have a UUID. In the above, the PARTUUID of my LUKS partition with the detached header was "3c9d04af-02".
When they accept my pull request, this issue will be resolved.
Your problem is using UUID instead of PARTUUID. With a detached header, you should be using the partition's UUID since there can be no filesystem UUID
The headerless volume won’t have a PARTUUID if it exists on an unpartitioned device.
Upon reviewing #1838, it doesn’t seem to hinge on having a PARTUUID.
#1838 may provide a workaround, though. If it works for headerless LUKS volumes on partitioned devices, I don’t see why it wouldn’t also work for the same on unpartitioned devices.
When they accept my pull request, this issue will be resolved.
Considering #1838 doesn’t fix the problem with /etc/block_uuid, no, it won’t.
@atweiden
Have you tried to include /etc/crypttab into the initramfs ?
I understand there are clearly bugs (e.g. invalid /etc/block_uuid.map), but my first approach would be to find at least one way to make this scenario work first.
You might know more about this topic than I do, but I found this post that might be helpful - https://linuxconfig.org/how-to-use-luks-with-a-detached-header
@atweiden Thanks. What happens if you delete the incorrect /etc/block_uuid.map from initramfs, and supply a correct /etc/crypttab ?
Removing block_uuid.map (altering modules.d/90crypt/*.sh to remove references to block_uuid.map, accordingly) doesn’t make a difference.
Removing
block_uuid.map(alteringmodules.d/90crypt/*.shto remove references toblock_uuid.map, accordingly) doesn’t make a difference.
@atweiden Thanks. I would have just post-process the initramfs (uncompress, remove file, decompress), but probably would have lead to the same result then (dracut also has a --keep option that lets use skip the uncompress part).
So this seems to indicate that fixing the issue regarding block_uuid.map would not actually make this particular scenario work. Perhaps it is better to focus on the validity of the /etc/crypttab file.
Can you please share your /etc/crypttab file ?
So this seems to indicate that fixing the issue regarding block_uuid.map would not actually make this particular scenario work. Perhaps it is better to focus on the validity of the /etc/crypttab file.
That’d be a happy outcome.
My /etc/crypttab looks like this (in voidvault 1FA/2FA mode):
vault PARTUUID=88064a44-6e50-4771-8ee4-2a2cf56e3748 /boot/keys/root.key luks,force,header=/boot/headers/root.header
bootvault UUID=7e6b1353-eb9c-4d7e-9247-2a35817a29c3 /root/keys/boot.key luks
The idea is, roughly:
- Enter GRUB password (
GRUB_ENABLE_CRYTPODISK=y) to unlock LUKS-encrypted boot volume, facilitating initramfs access - Line 1 of
/etc/crypttabunlocks LUKS-encrypted root volume using detached header (stored in/boot/headers/root.header, and included in initramfs) - Line 2 of
/etc/crypttabunlocks LUKS-encrypted boot volume using key stored in/root/keys/boot.key
@atweiden Can you help and try to come up with the "minimal" setup to reproduce the problem ?
I would just have one line in /etc/crypttab with detach headers and make it work and once that is working add back more complexity.
In the article, there seems to be 3 scenarios that worked (assuming the article is correct)
1. sdb_crypt /dev/sdb none luks,header=/dev/sdc
2. sdb_crypt /dev/sdb none luks,header=/path/to/header.img:/dev/sdc1
3. sdb_crypt /dev/sdb none luks,header=/path/to/header.img:UUID=<filesystem-uuid>
The examples all use none instead of a key ? Perhaps you can try that and perhaps thats more important than the detached header ?
I would just have one line in /etc/crypttab with detach headers and make it work
The root volume with detached headers already gets unlocked properly — that part works.
It’s the boot volume (see: “bootvault”, /etc/crypttab line 2) which doesn’t get unlocked.
Can you help and try to come up with the "minimal" setup to reproduce the problem ?
Void + Runit via Voidvault is already rather minimal. I suppose I could rewrite the whole thing in Bash, but it’d be easier to switch initramfs generators, frankly.
It’s been a few months since I last went spelunking through dracut’s source code, but I still find the following two factors a bit curious:
-
dracut’s
/etc/block_uuid.mapwriter implementation returnsnilinstead of the root volume UUID whenever the root volume is without headers — the root volume may only have a PARTUUID or serial ID in these cases -
When the root volume’s headers are detached, the dracut-related kernel command line (
/etc/default/grubin Void) containsrd.luks.partuuidorrd.luks.serial(as opposed tord.luks.uuid, as is commonplace)
Might this issue be caused by the dracut crypt module’s /etc/block_uuid.map handler inadvertently missing a matching PARTUUID or serial ID in /etc/block_uuid.map? I hypothesize the issue is /etc/block_uuid.map is fundamentally inadequate for handling LUKS volumes with detached headers.
There exists little code examples (or even, aside from a few obscure mailing list discussions, any open discussions) pertaining to detaching headers from the root LUKS volume, as Voidvault achieves. If you have the spare time and inclination, I’d encourage you to bootstrap Voidvault in a VirtualBox VM — the repo contains instructions. Just be sure to run voidvault new 1fa instead of voidvault new to bootstrap the root volume with detached headers.
There is always a luks UUID even for the drive with no partitions nor the header which is detached. You can take the luks UUID from the detached header stored separately somewhere else by using the command like this cryptsetup luksUUID /boot/header.img or cryptsetup luksDump /boot/header.img and it's a valid UUID for luks.uuid/rd.luks.uuid as the kernel parameter, but you need to specify luks.data too.
I set the kernel parameters in /etc/default/grub:
GRUB_CMDLINE_LINUX="luks.uuid=51d4d661-9fc4-42ee-8960-424c9f647d35 luks.data=51d4d661-9fc4-42ee-8960-424c9f647d35=/dev/sdb luks.options=51d4d661-9fc4-42ee-8960-424c9f647d35=header=/header.img:UUID=0663-66C7 luks.key=51d4d661-9fc4-42ee-8960-424c9f647d35=/luks-key:UUID=0663-66C7"
where 51d4d661-9fc4-42ee-8960-424c9f647d35 is the UUID taken from my header.img which is on a separate flash drive with UUID=0663-66C7 and /dev/sdb is the actual data disk with no partitions. Probably the same principle can be applied to crypttab.
@wowpetr In my case, the headerless (root) LUKS volume is successfully unlocked on startup. It’s the boot volume, a normal LUKS volume, which isn’t unlocked on startup.
Restated, atweiden/voidvault stores the root LUKS volume detached header in a second, separately LUKS-encrypted “boot” volume. It is this boot volume which is not unlocked. The root volume with detached header is successfully unlocked — my dracut settings appear to be working there.
@wowpetr, It just dawned on me your idea may be to patch in support for luksUUID in /etc/block_uuid.map. This way, there would at least be something there rather than extraneous whitespace caused by blkid $_dev -s UUID -o value returning nil. This may be a useful direction to go in considering the issue I’m having in Voidvault, where the root headerless volume on an unpartitioned device is successfully unlocked yet the normal LUKS boot volume isn’t — I’m assuming due to the missing element in /etc/block_uuid.map.
I have nothing further to add at the moment. I just didn’t want this thought to fade into the ether, as AFAIK no progress has been made here in several months.
Here's the workaround I used:
# /usr/lib/dracut/modules.d/90crypt/cryptroot-ask.sh:137
if luksheaderlabel=$(getargs "rd.luks.header.label"); then
printf "Please plug in the security key.\n"
while ! test -e /dev/disk/by-label/$luksheaderlabel; do
sleep 1;
done
mkdir -p /tmp/cryptroot-header
mount /dev/disk/by-label/$luksheaderlabel /tmp/cryptroot-header -o ro
luksheaderfile=$(getargs "rd.luks.header.file")
cryptsetupopts="$cryptsetupopts --header=/tmp/cryptroot-header/$luksheaderfile"
fi
unset luksheaderfile