slashbeast / better-initramfs

Small and reliable initramfs solution supporting (remote) rescue shell, lvm, dmcrypt luks, software raid, tuxonice, uswsusp and more.
BSD 3-Clause "New" or "Revised" License
318 stars 54 forks source link

GPG support ? (root_key & root_keydev) #54

Open jeandestouches opened 2 years ago

jeandestouches commented 2 years ago

Hi, Would it be possible to add root_key & root_keydev parameter + GPG support ? To be able to boot a vmlinuz kernel (with better-initramfs embedded into it) stored on an (unencrypted) USB key alongside a keyfile.gpg, which then unlocks the main drive. (LUKS) At boot, better-initramfs would provide a prompt to decrypt the gpg key, similar to what it does with askpass & cryptsetup. (using something like : gpg --decrypt /mnt/usb/keyfile.gpg | run cryptsetup --keyfile=- luksOpen [...] ) Of course, the USB key would be need to be mounted on /mnt/usb before that, using root_keydev to grab the UUID and root_key to avoid hardcoding "keyfile.gpg" in the init file and allow to pass the keyfile name as a parameter.

Similar to what sakaki achieved here : https://wiki.gentoo.org/wiki/User:Sakaki/Sakaki%27s_EFI_Install_Guide/Preparing_the_LUKS-LVM_Filesystem_and_Boot_USB_Key#Creating_a_Password-Protected_Keyfile_for_LUKS

sakaki recommends gnupg 1.4.x ("latest" being 1.4.23, which compiles fine on musl for information, I tried with sakaki's staticgpg ebuild bumped to 1.4.23 on a gentoo musl vm) : "Unfortunately, the version of gpg that is emerged by Portage by default is the 2.x variant. This requires a (rather convoluted) service known as pinentry to ask you for your password (even when compiled statically), and currently genkernel's initramfs builder (and init script) does not work correctly with it. Instead, genkernel expects to be using a version 1.x gpg which can query for passphrases itself, without invoking an outside agent."

(this might be old info, maybe it is possible to use latest gnupg instead now, I don't know)

https://wiki.gentoo.org/wiki/User:Sakaki/Sakaki%27s_EFI_Install_Guide/Building_the_Gentoo_Base_System_Minus_Kernel https://github.com/sakaki-/sakaki-tools/blob/master/app-crypt/staticgpg/staticgpg-1.4.16-r1.ebuild

Thanks. (using better-initramfs for more than a year now, really nice!)

slashbeast commented 2 years ago

Adding support for it is not that hard however I am unsure if that would provide any security benefit at all.

In your use case you will boot of off pendrive, be prompted for password and then just boot. Inside it will boot kernel, start initramfs, ask for password for GPG keyfile, decrypt it and then use it to pass it to cryptsetup.

However with current state of binit, you can do the same, just without GPG. How does it help here that you would provide password for GPG keyfile as instead to password for LUKS's keyslot?

jeandestouches commented 2 years ago

The main idea was having dual-factor security; I quote sakaki's own words for clarity.

"The point of this is to establish dual-factor security - both the (encrypted) keyfile, and your passphrase (to decrypt it) will be required to access the LUKS data stored on the target machine's hard drive. This means that even if a keylogger is present, should the machine be stolen - powered down but without the USB key - the LUKS data will still be safe (as the thief will not have your encrypted keyfile). Similarly, (assuming no keylogger!) if your machine were to be stolen powered down but with the USB key still in it, it will also not be possible to access your LUKS data (as in this case the thief will not know your passphrase)."

But the more I read that, the more I realize it's indeed a bit overkill...

slashbeast commented 2 years ago

I am leaning toward calling it a cargo cult security. While indeed you do need two 'factors' to unlock it yourself, anyone who can attack you needs a physical access, and then you have single LUKS key to crack, you do not need anything else. The way that LUKS works is that there's a key that is then encrypted with keyslots, you can have multiple unlock keys / passwords, and all will decrypt the same key.

The same level of security would give you detached LUKS header, where the encryption key is on your pendrive, so you need pendrive (header, encrypted key) + password to unlock it and I think I'd be more keen to add the detached header support over the GPG feature.

Thoughts?

jeandestouches commented 2 years ago

100% agree. This is better indeed. Maybe there are some other use case of GPG support in better-initramfs, but regarding the original goal, this is essentially what I'm looking for. (example here : https://wiki.archlinux.org/title/Dm-crypt/Specialties#Encrypted_system_using_a_detached_LUKS_header ) Thanks for reading, cheers.

slashbeast commented 2 years ago

I will look into the detached headers then. You could even embed the header together with initramfs into your kernel image, even more, with EFI STUB enabled you could even put such kernel as EFI/BOOT/BOOTX64.EFI on fat32 partition and boot it without any bootloader.

jeandestouches commented 2 years ago

Nice, I tried that (with a qemu vm and some loop devices), it works great. I only needed to modify the cryptsetup command to read :

run cryptsetup luksOpen --tries 3 --header /header.img ${cryptsetup_args} "${enc_dev}" "${dev_name}"

(and also copied header.img to /usr/src/initramfs)

CONFIG_CMDLINE="luks enc_root=/dev/sdb lvm root=UUID=82d0add1-9f79-4009-a2e1-0d379997c036 rootfstype=ext4 keymap=fr net.ifnames=0 biosdevname=0 acpi_osi=Linux rescueshell"

(/dev/sda being the "USB" device here, fat32 formatted with EFI/BOOT/BOOTX64.EFI)

I added rescueshell here because I wanted to see if there was a way to use /dev/disk/by-id (or path) instead of /dev/sdb (the whole disk is encrypted with detached LUKS header in the test I made, no partition) so I can't use UUID here for enc_root. I wonder if it is possible to have that without udev, apparently not except eventually using lsscsi.

I found some reading about that here : https://unix.stackexchange.com/questions/278345/command-to-generate-dev-disk-by-path-name-on-a-system-without-udev-daemon

Let me know what you think or correct me if I'm wrong.

slashbeast commented 2 years ago

I actually plan to add real udev into initramfs since unless you run udev at initramfs level and then move around /run/udev to newroot otherwise systemd's lvm service might be confused and lsblk is unable to get all its outputs. I already did a huge update in devel branch with new sysroot, new version and root-less building. So stay tuned and you will get /by-id/, this is the next feature I work on.

jeandestouches commented 2 years ago

Thanks ! By the way, could you mention on the ChangeLog that mknod calls are removed. (related to root-less building I assume) I learned it the hard way (my fault, I should have read the full commit log..) when building with the new devel branch. Yes, I use an embedded initramfs on a headless system, so I was missing the /dev/console,null,random,tty,urandom,zero :sob: At first, I thought it was a dropbear issue since I was able to ping the system but ssh was unavailable.. Well, it works fine again after I put back the old /dev/* again.

slashbeast commented 2 years ago

This is very interesting problem. the nodes are either created on boot or via devtmpfs long before dropbear starts so even if they're not present, it must work.

The only one case I remember where it was a problem was actually lack of /dev/console when initramfs is embedded, but if it booted for you, that must be not the case. Can you debug it a bit more and create separated bug report for it? Then I can address it somehow, maybe via separated script that does cpio archive that always include them even if those are not part of sourceroot/dev.