Hi folks,

I have Alpine Linux installed in an encrypted LUKS partition. I came across this tutorial which shows how to setup a key in a USB drive and when the drive is inserted and the computer booted, the LUKS partition auto-unlocks with the key on the USB drive.

https://askubuntu.com/questions/1414617/configure-ubuntu-22-04-zfs-for-automatic-luks-unlock-on-boot-via-usb-drive

I would like to setup the same thing but I do not have Alpine linux installed on ZFS, so I’m looking for ways to adapt the instructions.

So far, what I’ve done is:

  1. I’ve setup the key on the usb stick and I can unlock the LUKS partition with that key.
  2. create a /etc/mkinitfs/features.d/usb-unlock.sh script with the following content:

(the echo to /dev/kmesg was to check whether the script did indeed run at boot by trying to print to the kernel messages but I can’t find anything in the kernel messages).

#!/bin/sh

echo "usb-unlock script starting..." > /dev/kmsg

USB_MOUNT="/mnt/my-usb-key" # The USB stick mounting point
LUKS_KEY_FILE="awesome.key"  # The name of your keyfile on the USB stick

# Search for the USB stick with the key
for device in $(ls /dev/disk/by-uuid/*); do
    mount $device $USB_MOUNT 2>/dev/null
    if [ -f "$USB_MOUNT/$LUKS_KEY_FILE" ]; then
        # Unlock the LUKS partition
        cryptsetup luksOpen /dev/sda3 cryptroot \
            --key-file "$USB_MOUNT/$LUKS_KEY_FILE" && exit 0
    fi
    umount $USB_MOUNT
done
echo "No USB key found, falling back to password prompt." # this message never appears, despite not having found the key on the usb stick

echo "usb-unlock script ending." > /dev/kmsg
  1. I added usb-unlock to the features in mkinitfs.conf:
mytestalpine:~# cat /etc/mkinitfs/mkinitfs.conf 
features="ata base ide scsi usb virtio ext4 cryptsetup keymap usb-unlock"
  1. run mkinitfs to rebuild the initramfs. Then reboot to test the implementation, which was unsuccessful.

What am I missing / doing wrong? Thank you for your help!

Edit: forgot to add step 4

  • The HobbyistOP
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    4 days ago

    Thank you for your help.

    I decided to give dracut a shot, see how far I could get.

    I created a directory /usr/lib/dracut/modules.d/99usb-mount in which I created two scripts: A first module /usr/lib/dracut/modules.d/99usb-mount/module-setup.sh, executable:

    #!/bin/bash
    
    check() {
        return 0
    }
    
    depends() {
        echo "crypt"
        return 0
    }
    
    install() {
        inst_hook pre-mount 90 "$moddir/usb-mount.sh"
    }
    

    And a second script /usr/lib/dracut/modules.d/99usb-mount/usb-mount.sh, also executable:

    #!/bin/bash
    
    LUKS_PARTITION=/dev/sda3
    USB_NKL=/dev/disk/by-uuid/<MY-UUID>
    USB_MOUNT_DIR=/mnt/my-usb/
    KEY_FILENAME=mykey.key
    
    # Wait for the USB to be detected and available
    for i in {1..10}; do
        if [ -b ${USB_NKL} ]; then
            break
        fi
        sleep 1
    done
    
    # Mount the USB stick
    mount ${USB_NKL} ${USB_MOUNT_DIR}
    
    # Check if the mount was successful
    if [ $? -ne 0 ]; then
        echo "Failed to mount USB stick"
        exit 1
    fi
    
    # Unlock the LUKS partition using the keyfile
    if [ -e "${USB_MOUNT_DIR}/${KEY_FILENAME}" ]; then
        cryptsetup luksOpen "${LUKS_PARTITION}" cryptroot --key-file "${USB_MOUNT_DIR}/${KEY_FILENAME}"
    else
        echo "Keyfile not found!"
        echo "Failed to unlock LUKS partition"
        exit 1
    fi
    

    I then fixed some dependencies and got around installing device-mapper, providing dmsetup, required by dm, required by crypt, required by my scripts.

    Then I ran: dracut -f, which didn’t seem to have any issue and includes my module:

    [...]
    dracut[I]: *** Including module: usb-mount ***
    [...]
    dracut[E]: ldconfig exited ungracefully
    [...]
    dracut[I]: *** Creating initramfs image file '/boot/initramfs-6.6.54-0-lts.img' done ***
    

    Not sure if this ldconfig error should be of any concern? The end image seems to have been created successfully.

    When I check the verbose output, I see my module being included:

    dracut[D]: -rwxr-xr-x 0/0       747 2024-10-07 22:30:00 lib/dracut/hooks/pre-mount/90-usb-mount.sh
    

    However, it is here numbered 90 when above I had placed it in 99, no idea what that’s about? (edit: actually I wrote 90 in the module-setup.sh, so this is normal I guess).

    Then I rebooted with my key and the prompt for my password to unlock my LUKS partition still appeared.

    In the kernel messages I see my usb stick being detected (perhaps not mounted?) prior to the password prompt, so not sure what’s going on. Do you see any issue with my attempt? Or would you happen to have any propositions for debugging this further? I’m a bit lost as to how I can diagnose the issue.

    Here are the kernel messages regarding the usb detection and a few seconds later, me unlocking the LUKS partition:

    [    1.748076] usb 1-1: new high-speed USB device number 2 using xhci_hcd # usb 1-1 / sdb is my USBkey. It seems to have been detected but not mounted?
    [    2.068060] device-mapper: uevent: version 1.0.3
    [    2.068190] device-mapper: ioctl: 4.48.0-ioctl (2023-03-01) initialised: [email protected]
    [    2.078157] Key type encrypted registered
    [    2.153792] usb 1-1: New USB device found, idVendor=067b, idProduct=2517, bcdDevice= 1.00
    [    2.153799] usb 1-1: New USB device strings: Mfr=1, Product=4, SerialNumber=6
    [    2.153801] usb 1-1: Product: ClipDrive
    [    2.153803] usb 1-1: Manufacturer: BUFFALO
    [    2.153805] usb 1-1: SerialNumber: A9200502030000221
    [    2.155494] usb-storage 1-1:1.0: USB Mass Storage device detected
    [    2.157341] scsi host3: usb-storage 1-1:1.0
    [    2.159772] usbcore: registered new interface driver uas
    [    3.221531] scsi 3:0:0:0: Direct-Access     BUFFALO  ClipDrive        1.00 PQ: 0 ANSI: 0 CCS
    [    3.224250] sd 3:0:0:0: [sdb] 507904 512-byte logical blocks: (260 MB/248 MiB)
    [    3.227885] sd 3:0:0:0: [sdb] Write Protect is off
    [    3.227899] sd 3:0:0:0: [sdb] Mode Sense: 23 00 00 00
    [    3.231635] sd 3:0:0:0: [sdb] No Caching mode page found
    [    3.231645] sd 3:0:0:0: [sdb] Assuming drive cache: write through
    [    3.247551] sd 3:0:0:0: [sdb] Attached SCSI removable disk
    [    6.323670] EXT4-fs (dm-0): orphan cleanup on readonly fs   # the 3 seconds gap is me unlocking the LUKS using the keyboard
    [    6.323954] EXT4-fs (dm-0): mounted filesystem 33a8b408-37ff-4b8a-98bf-bba8b6f00604 ro with ordered data mode. Quota mode: none.
    [    6.324134] Mounting root: ok.
    
    • chameleon@fedia.io
      link
      fedilink
      arrow-up
      2
      ·
      3 days ago

      Dracut may have this functionality already built in via rd.luks.key, so a custom module would really only make sense if you’re trying to do more than that. You can probably get away with just using that if you just want it to work, but if you want to customize stuff:

      I suspect your module is running well after the device is already supposed to be cryptsetup opened. The way the default crypt module handles it is by setting up udev configuration in a very early phase, and then having udev request the password a little bit later when it finds the device it’s trying to open, until all devices are ready. It’s a complex mechanism compared to Alpine’s straightforward script, but it’s much more flexible when it comes to ordering of things like RAID/network devices/LUKS/etc.

      The result of that is that your code would have to run much earlier. There’s some documentation on how hooks work, and the builtin rd.luks.key / keydev handler runs at cmdline 10. That’s well before your pre-mount, and probably where you’d want to run your code. Based on a cursory inspection of the other code, you could either cryptsetup open it yourself if you use the name it expects (rd.luks.name= cmdline parameter or luks-$luks_container_uuid), or you could use that /tmp/luks.keys mechanism (it’s a dracut-internal thing so you won’t find much documentation, but it lives in crypt-lib.sh, cryptroot-ask.sh and probe-keydev.sh).

      As for debugging, the cmdline manpage has a few decent enough options. rd.break=cmdline or similar can force a shell before Dracut goes through a specific phase of hooks. You should be able to manually test doing things similar to your script at that point.