brandsimon / verity-squash-root

Build signed efi binaries which mount a dm-verity verified squashfs image as rootfs on boot.
MIT License
23 stars 4 forks source link

Help with squash root encryption please #55

Closed MorningLightMountain713 closed 3 months ago

MorningLightMountain713 commented 3 months ago

H ithere, thanks for this great package.

I have this same config working for verity-squash-root without encryption.

However I just can't figure out how to get encryption working with a tpm2 on the squashfs partition.

System:

davew@porridge:~$ uname -a
Linux porridge 6.1.0-21-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.90-1 (2024-05-03) x86_64 GNU/Linux

I can get encryption working if I do the following:

Reboot and the encrypted drive is unlocked via tpm.

However, when I choose the verity-squash-root current from the efi boot menu, instead of the above, it hangs.

Here are my config files:

verity-squash-root config:

root@porridge:~# cat /etc/verity_squash_root/config.ini
[DEFAULT]
# If CMDLINE is not configured, use /etc/kernel/cmdline
CMDLINE = root=LABEL=root
EFI_STUB = /usr/lib/systemd/boot/efi/linuxx64.efi.stub
DECRYPT_SECURE_BOOT_KEYS_CMD = age -d -o {} /etc/verity_squash_root/keys.tar.age

# DECRYPT_SECURE_BOOT_KEYS_CMD =
#     openssl enc -aes-256-cbc -pbkdf2 -d
#     -in /etc/verity_squash_root/keys.tar.openssl -out {}
# DECRYPT_SECURE_BOOT_KEYS_CMD = cp /etc/verity_squash_root/keys.tar {}
EXCLUDE_DIRS = /home,/opt,/srv,/var/!(lib|log)
EFI_PARTITION = /boot/efi
ROOT_MOUNT = /mnt/root
IGNORE_KERNEL_EFIS =

[EXTRA_SIGN]
# These files will be signed when called with sign_extra_files
# The format is: `NAME = SOURCE_PATH => DESTINATION_PATH`
# Be careful to not sign files from untrusted sources,
# e.g. the ESP partition. An attacker could exchange these
# files.
systemd = /usr/lib/systemd/boot/efi/systemd-bootx64.efi => /boot/efi/EFI/systemd/systemd-bootx64.efi
nix = /vmlinuz => /boot/efi/f314a67efb344947bba5f1273222b637/6.1.0-21-amd64/linux

/etc/crypttab (and /etc/crypttab.initramfs):

root@porridge:~# cat /etc/crypttab
# <target name> <source device>     <key file>  <options>
crypt LABEL=luks none luks

fstab:

root@porridge:~# cat /etc/fstab
UUID=eadbec4a-c01f-4041-816f-c32222ba6176 /               ext4    errors=remount-ro 0       1
UUID=1910-BD80  /boot/efi       vfat    umask=0077      0       1
LABEL=root /mnt/root     ext4 defaults 0 2

ids:

root@porridge:~# blkid
/dev/sr0: BLOCK_SIZE="2048" UUID="2024-02-10-11-31-15-00" LABEL="Debian 12.5.0 amd64 n" TYPE="iso9660" PTUUID="34862533" PTTYPE="dos"
/dev/mapper/crypt: LABEL="root" UUID="a5aa816c-0295-40ea-8857-2b1d04aa8394" BLOCK_SIZE="4096" TYPE="ext4"
/dev/sda2: UUID="eb7642ba-8c51-487a-bf2f-af92a521eaf4" LABEL="luks" TYPE="crypto_LUKS" PARTUUID="677d0201-3513-4888-a9d0-e819a915a180"
/dev/sda3: UUID="eadbec4a-c01f-4041-816f-c32222ba6176" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="647adfe5-7356-484a-9981-6e82393fb801"
/dev/sda1: UUID="1910-BD80" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="d1bc7784-b91e-4fb9-ad62-2e54db656c57"

Choosing the writeable overlay (note encryption works fine with the top option)

Screenshot 2024-05-24 at 1 34 11 PM

Gets stuck during boot timing out waiting for the /dev/mapper/root to unlock (LABEL=root)

Screenshot 2024-05-24 at 1 36 52 PM

What can I do to get this working?

Thanks

MorningLightMountain713 commented 3 months ago

I've got to the point where if I wait for the above to drop a shell, I can run the following, and it will unlock the drive. (I added /sbin/cryptsetup via dracut)

I'm just trying to figure out what systemd-cryptsetup service isn't opening it automatically

Screenshot 2024-05-24 at 4 46 09 PM

MorningLightMountain713 commented 3 months ago

okay so I figured this out (mostly)

Had to do two things:

from /etc/veritiy-squash-root/config.ini:

CMDLINE = root=LABEL=root rd.luks.name=eb7642ba-8c51-487a-bf2f-af92a521eaf4=flux_crypto rd.luks.data=eb7642ba-8c51-487a-bf2f-af92a521eaf4=/dev/sda2 rd.luks.options=eb7642ba-8c51-487a-bf2f-af92a521eaf4=luks,tpm2-device=auto,discard

While this works, it's less than ideal. The reason I was using the crypttab file was that I could label the crypt partition, i.e. keep it generic.

It seems the dracut crypt module overwrites the /etc/crypttab in the initramfs. So even if you copy it with Install_items, it gets overwritten.

I would much prefer to use the crypttab file instead of having to hardcode the UUID.

At least this is partially working. Solid 2 days to get here ha.

brandsimon commented 3 months ago

@MorningLightMountain713

Hi, thank you very much for the feedback. As you figuered out, dracut recreates the crypttab and it's autodetection does not always detect the correct entries. You can force dracut to add a line, if you add the force option, e.g.:

rootcrypt UUID=... - tpm2-device=auto,discard,force

Does this work for you?

MorningLightMountain713 commented 3 months ago

@brandsimon

Thanks for the pointer. Didn't know you could do that. (I have since tried, and didn't work)

I guess the problem I have is that I want the UKI to be portable, so I can't specify the UUID in the kernel params. That's why I was hoping to use a label from /etc/crypttab

Whatever I do, I can't seem to get dracut to respect the /etc/crypttab file. systemd-cryptsetup-generator only seems to work with kernel params, which are missing the label option.

I guess the other problem, is tht even if I get the crypttab file working, there is no way to exclude it from the squashfs, as it will generate an error if it's in both initramfs and root fs.

I'll keep hacking away.

Edit:

On a test system with /etc/crypttab, If I run the following, it looks to generate the correct systemd unit file:

 /usr/lib/systemd/system-generators/systemd-cryptsetup-generator /etc/systemd/system

I just need to figure how to get dracut crypt to run it

brandsimon commented 3 months ago

@MorningLightMountain713

Interesting. The force option creates the correct crypttab file, but dracut still does not unlock the partition? Have you tried to forcefully add the crypt module when using the crypttab file? add_dracutmodules+=" crypt " Probably dracut does not recognize that it is needed, when it does not manually detect entries in crypttab or the command line.

there is no way to exclude it from the squashfs Yes, I think so too. A portable way would be to use LABELs instead of UUIDs. Then every computer needs to label the root partition. It sounds quite interesting, what you are doing. Do you want to distribute one verity-squash-root image to multiple servers?

MorningLightMountain713 commented 3 months ago

@brandsimon

I got this working, welll, kind of :P

After trawling through 90crypt/module_setup.sh I realized that it will only generate the crypttab file if in hostonly mode. I have been trying to build with hostonly=no (trying to build a generic kernel)

To me, it seems like the dracut crypt module has been built with the assumption that the crypttab file is for local builds only - I believe this doesn't always hold true (my usecase); using labels in the crypttab, it's portable.

I think in the interim, to get it to build, I'll modify the crypt module with an override to generate the crypttab file regardless of hostonly.

I have to do more digging on this next part, I'm not sure how the /etc/block_uuid.map file affects things. I noticed crypt install() was missing LABEL parsing, so I added the following, so my entry gets added correctly:

[[ $_dev == LABEL=* ]] \
        && _dev="/dev/disk/by-label/${_dev#LABEL=}"

I will test again with the above removed on another build and see if it still works.

To get it to boot, I had to hack verity_squash_root/image.py and add a line to exclude the crypttab file from the squashfs:

I guess it wouldn't be hard to make the excludes more generic, where it stats the target and checks if it's a file or a dir, if a file, just exclude it, or if a directory, do the current operation?

    for d in include_empty_dirs:
        sd = d.strip("/")
        cmd += ["{}/*".format(sd)]
        cmd += ["{}/.*".format(sd)]
    cmd += ["etc/crypttab"]

My Usecase:

I'm running software on untrusted hardware, where an "operator" would install the software and the secure boot keys and thats it. It would run autonomously, more like an embedded system.

I need to validate the state of the system, and ensure it hasn't been tampered with, hence why verity-squash-root is a really good fit.

There are many of these "systems" all with different hardware, so it has to be generic.

What I'm doing, is on a build system, building the UKI and squashfs. Then I'll distribute the UKI, squashfs and secure boot certificates, and keep the keys private.

I'm going to start playing with using verity-squash-root and debootstrap / chroot.

The only other problem I'm having is installing the pk.auth file with efi-updatevar. I see quite a bit of info on the internet that its firmware dependent (the db and kek files install fine). The thing I don't understand, is that sbctl can do it from within the os without having to load into firmware-setup; I need to research this more.

Thanks for your help - and again, appreciate the great software.

brandsimon commented 3 months ago

@MorningLightMountain713 Sorry for the delay, I was on vacation. If I remember correctly,hostonly=no also has some security related side-effects, e.g. no password prompt, if an error happens during the boot process, which could give a local attacker full access. (e.g. this is especially relevant, if your security model uses a TPM2 to protect data).

I guess it wouldn't be hard to make the excludes more generic

The code excludes everything in the directory, so the directory will be included in the image. This is a workaround for a issue in mksquashfs: https://github.com/plougher/squashfs-tools/issues/189 I will check, if distributions use a newer version of squashfs-tools and if so, remove the workaround, which should support your use-case.

Your use-case sounds really interesting and verity-squash-root a good fit. If it will be open-source, I'd love to have a look. Feel free to contact me via mail if you want to chat about it.

The only other problem I'm having is installing the pk.auth file with efi-updatevar

I don't have a lot of knowledge about the sbctl or efi-updatevar. I install the db key first, than the kek and the pk last, because it will set the system from setup mode into user mode, which prevents most modifications. systemd-boot has an option to install secure boot keys automatically at boot (secure-boot-enroll), not sure if any of that does really help with your problem.

MorningLightMountain713 commented 3 months ago

@brandsimon

I have just got back from vacation myself.

Thanks for the info. Yes, it's open source.

I'm just working on a distributable ISO at the moment. I'll drop you a line via email once I have something workable and share some code.

Cheers!