User:Wolegis/Remote unlocking

From ArchWiki

Remote unlocking of root (or other) partition

Imagine a system with one or more LUKS encrypted partitions (root or others) or volumes and you need to unlock these partitions/volumes during startup. In this case you need to be able to log in from remote and provide a password during an early boot phase. This can be achieved by using one or more mkinitcpio hook(s) that configure a network interface and start some kind of SSH server. Some packages listed below contribute various mkinitcpio build hooks to ease the configuration.

Note:
  • Keep in mind to use kernel device names for the network interface (e.g. eth0) and not udev's ones (e.g. enp1s0), as those will not work.
  • By default, Predictable Network Interface Names are activated and change the kernel device name during late boot. Use dmesg and look what your Network kernel module does to find the original name (e.g. eth0)
  • It could be necessary to add the module for your ethernet or wireless network card to the MODULES array.

Busybox based initramfs (built with mkinitcpio)

For busybox based initramfs the packages mkinitcpio-netconf and/or mkinitcpio-pppAUR provide network connectivity. As SSH server you have the option of using either mkinitcpio-dropbear or mkinitcpio-tinyssh. Those hooks do not install any shell, so you also need to install the mkinitcpio-utils package. The instructions below can be used in any combination of the packages above. When there are different paths, it will be noted.

  1. If you do not have an SSH key pair yet, generate one on the client system (the one which will be used to unlock the remote machine).
    Note: tinyssh only supports Ed25519 and ECDSA key types without passphrase. If you chose to use mkinitcpio-tinyssh, you need to create/use one of these.
    Note: mkinitcpio-tinyssh currently has a bug affecting it's use of tinyssh-convert. See Github for details and a fix.
    Note: mkinitcpio-dropbear in version 0.0.3-5 is not compatible with the current dropbear implementation that removed dss. See Github for details and a fix.
  2. Insert your SSH public key (i.e. the one you usually put onto hosts so that you can ssh in without a password, or the one you just created and which ends with .pub) into the remote machine's /etc/dropbear/root_key or /etc/tinyssh/root_key file.
    Tip: This method can later be used to add other SSH public keys as needed; In the case of simply copying the content of the remote's ~/.ssh/authorized_keys, be sure to verify that it only contains keys you intend to be using to unlock the remote machine. When adding additional keys, regenerate your initrd as well using mkinitcpio. See also OpenSSH#Protection.
  3. Add all three <netconf and/or ppp> <dropbear or tinyssh> encryptssh hooks before filesystems within the "HOOKS" array in /etc/mkinitcpio.conf (the encryptssh replaces the encrypt hook). Then regenerate the initramfs.
    Note: The net hook provided by mkinitcpio-nfs-utils is not needed.
  4. Configure the required cryptdevice= parameter and add the ip= kernel command parameter to your boot loader configuration with the appropriate arguments. For example, if you want the IP address to be assigned by DHCP, you can use the following parameter:
    ip=dhcp
    This is most useful if your DHCP server is configured to always assign the same IP for this host, as otherwise accessing the system via SSH is going to be difficult. In that case, you can use a static IP:
    ip=192.168.1.1:::::eth0:none
    Alternatively, you can also specify the subnet mask and gateway required by the network:
    ip=192.168.1.1::192.168.1.254:255.255.255.0::eth0:none
    Note: As of version 0.0.4 of mkinitcpio-netconf, you can nest multiple ip= parameters in order to configure multiple interfaces. You cannot mix it with ip=dhcp (ip=:::::eth0:dhcp) alone. An interface needs to be specified.
    ip=ip=192.168.1.1:::::eth0:none:ip=172.16.1.1:::::eth1:none
    If using DHCP, consider adding the netconf_timeout= kernel parameter, to prevent netconf from trying to obtain an IP forever. For a detailed description of the ip= parameter, have a look at the according mkinitcpio section. When finished, update the configuration of your boot loader.
  5. Finally, restart the remote system and try to ssh to it, explicitly stating the "root" username (even if the root account is disabled on the machine, this root user is used only in the initrd for the purpose of unlocking the remote system). If you are using the mkinitcpio-dropbear package and you also have the openssh package installed, then you most probably will not get any warnings before logging in, because it convert and use the same host keys openssh uses (except Ed25519 keys, as dropbear does not support them). In case you are using mkinitcpio-tinyssh, a script tinyssh-convert is bundled, so you can use the same keys as your openssh installation (currently only Ed25519 keys). It may be required to manually copy the host key, via tinyssh-convert, to /etc/tinyssh/sshkeydir. In either case, you should have run the ssh daemon at least once, using the provided systemd units, so the keys can be generated first. After rebooting the machine, you should be prompted for the passphrase to unlock the root device. The system will complete its boot process and you can then ssh to it as you normally would (with the remote user of your choice).

Enabling WiFi

The netconf hook is normally used with an Ethernet connection. In case you want to setup a computer with wireless only, and unlock it via WiFi, you can use a predefined hook or create a custom hook to connect to a WiFi network before the netconf hook is run.

Predefined hook

You can install a predefined hook based on the one in this wiki:

  1. Install mkinitcpio-wifiAUR.
  2. Configure your WiFi connection by creating a wpa_supplicant configuration with your network properties:
    wpa_passphrase "ESSID" "passphrase" > /etc/wpa_supplicant/initcpio.conf
  3. Add the wifi hook before netconf in your /etc/mkinitcpio.conf. Your WiFi-related modules should be auto-detected, if not: add them to the MODULES section.
  4. Add ip=:::::wlan0:dhcp to the kernel parameters.
  5. Regenerate the initramfs.
  6. Update the configuration of your boot loader.
Custom hook

Below example shows a setup using a USB WiFi adapter, connecting to a WiFi network protected with WPA2-PSK. In case you use for example WEP or another initramfs generator, you might need to adjust accordingly.

  1. Modify /etc/mkinitcpio.conf:
    • Add the needed kernel module for your specific WiFi adapter.
    • Include the wpa_passphrase and wpa_supplicant binaries.
    • Add a hook wifi (or a name of your choice, this is the custom hook that will be created) before the net hook.
      MODULES=(module)
      BINARIES=(wpa_passphrase wpa_supplicant)
      HOOKS=(base udev autodetect ... wifi net ... dropbear encryptssh ...)
  2. Create the wifi hook in /etc/initcpio/hooks/wifi:
    run_hook ()
    {
    # Sleep a couple of seconds so wlan0 is setup by kernel
    sleep 5

    # Set wlan0 to up
    ip link set wlan0 up

    # Associate with WiFi network
    # 1. Save temp config file
    wpa_passphrase "network ESSID" "pass phrase" > /tmp/wifi

    # 2. Associate
    wpa_supplicant -B -D nl80211,wext -i wlan0 -c /tmp/wifi

    # Sleep a couple of seconds so that wpa_supplicant finishes connecting
    sleep 5

    # wlan0 should now be connected and ready to be assigned an ip by the net hook
    }

    run_cleanuphook ()
    {
    # Kill wpa_supplicant running in the background
    killall wpa_supplicant

    # Set wlan0 link down
    ip link set wlan0 down

    # wlan0 should now be fully disconnected from the WiFi network
    }
  3. Create the hook installation file in /etc/initcpio/install/wifi:
    build ()
    {
    add_runscript
    }
    help ()
    {
    cat<<HELPEOF
    Enables WiFi on boot, for dropbear ssh unlocking of disk.
    HELPEOF
    }
  4. Add ip=:::::wlan0:dhcp to the kernel parameters. Remove ip=:::::eth0:dhcp so it does not conflict.
  5. Optionally create an additional boot entry with kernel parameter ip=:::::eth0:dhcp.
  6. Regenerate the initramfs.
  7. Update the configuration of your boot loader.

Remember to setup WiFi, so you are able to login once the system is fully booted. In case you are unable to connect to the WiFi network, try increasing the sleep times a bit.

Systemd based initramfs (built with mkinitcpio)

For systemd based initramfs the AUR package mkinitcpio-systemd-extrasAUR provides a collection of build hooks (aka install hooks) to achieve network connectivity and SSH login during early boot. Depending on the concrete setup this either gives you access to the initramfs environment via busybox' dash or just a password prompt.

A minimal setup:

/etc/mkinitcpio.conf
HOOKS=(base systemd autodetect modconf keyboard sd-vconsole sd-network sd-tinyssh sd-encrypt
       block filesystems fsck)
SD_TINYSSH_COMMAND="systemd-tty-ask-password-agent --query --watch"

When building the initramfs with mkinitcpio this setup copies the already existing configuration of systemd-networkd from the main system and also tries to copy / convert existing SSH server keys from an existing TinySSH or OpenSSH installation. tinyssh needs to be installed (but not necessarily enabled) on the main system. There are additional configuration parameters in case systemd-networkd is not used by the main system. See the documentation of mkinitcpio-systemd-extrasAUR for further details.

Note: This section used to mention mkinitcpio-systemd-tool as another alternative to achieve remote login and LUKS unlocking during early startup. The approach is completely different as it requires only one additional hook systemd-tool and all further setup is done in special [X-SystemdTool] sections in systemd service files. The tool is poorly documented and has effectively been abandoned. Only 4 commits in 2021 and only one (insignificant) in 2022. (See commits, issue #92 and issue #97.) Nevertheless, it's still available as an official package in Extra.

Systemd based initramfs (built with dracut)

If you are using dracut instead of mkinitcpio, you might want to check out dracut-sshd as an alternative to the above options.