Remote disk unlocking: Difference between revisions

Onny (talk | contribs)
Add section on how to enable wifi in initrd
34j (talk | contribs)
mNo edit summary
 
(15 intermediate revisions by 7 users not shown)
Line 1: Line 1:
If you want to unlock your computer remotely via SSH or even through Tor, and you are facing the problem, that you can’t reach your computer before your computer is unlocked. Tor will help you to reach your computer, even during the boot process.
This page describes the method for <strong>remotely</strong> unlocking LUKS / ZFS encrypted root partition during boot process. SSH or even Tor may be used to access the system.


== Setup ==
== Setup ==


Generate host key for the SSH daemon which will run in initrd during boot
Generate host key for the SSH daemon which will run in initrd during boot (required)


<syntaxhighlight lang="bash">
<syntaxhighlight lang="console">
# ssh-keygen -t rsa -N "" -f /etc/secrets/initrd/ssh_host_rsa_key
# mkdir -p /etc/secrets/initrd
# ssh-keygen -t ed25519 -N "" -f /etc/secrets/initrd/ssh_host_ed25519_key
</syntaxhighlight>
</syntaxhighlight>


Line 12: Line 13:


{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
boot.kernelParams = [ "ip=dhcp" ];
boot.initrd = {
boot.initrd = {
   availableKernelModules = [ "r8169" ];
   availableKernelModules = [ "r8169" ];
  systemd.users.root.shell = "/bin/cryptsetup-askpass";
   network = {
   network = {
     enable = true;
     enable = true;
    udhcpc.enable = true;
    flushBeforeStage2 = true;
     ssh = {
     ssh = {
       enable = true;
       enable = true;
       port = 22;
       port = 22;
       authorizedKeys = [ "ssh-rsa AAAAyourpublic-key-here..." ];
       authorizedKeys = [ "ssh-rsa AAAAyourpublic-key-here..." ]; # The public key of the client (Not the public key created in the previous step) (required)
       hostKeys = [ "/etc/secrets/initrd/ssh_host_rsa_key" ];
       hostKeys = [ "/etc/secrets/initrd/ssh_host_ed25519_key" ]; # The path of the private key created in the previous step (required)
     };
     };
    postCommands = ''
      # unlock LUKS encrypted partitions
      echo 'cryptsetup-askpass'</nowiki> >> <nowiki>/root/.profile
      # unlock ZFS encrypted partitions (NOTE: boot.initrd.supportedFilesystems.zfs must be true for zfs, zpool to be available here)
      # zpool import -a;
      # echo 'zfs load-key -a'</nowiki> >> <nowiki>/root/.profile
      # exit SSH
      echo 'exit'</nowiki> >> <nowiki>/root/.profile
    '';
   };
   };
};
};
Line 32: Line 42:
* '''authorizedKeys''': Add the SSH public keys for the users which should be able to authenticate to the SSH daemon to the <code>authorizedKeys</code> option.
* '''authorizedKeys''': Add the SSH public keys for the users which should be able to authenticate to the SSH daemon to the <code>authorizedKeys</code> option.
* '''availableKernelModules''': Most likely your network card is not working without its kernel module being part of the initrd, so you have to find out which module is used for your network. Use <code>lspci -v | grep -iA8 'network\|ethernet'</code> for that.
* '''availableKernelModules''': Most likely your network card is not working without its kernel module being part of the initrd, so you have to find out which module is used for your network. Use <code>lspci -v | grep -iA8 'network\|ethernet'</code> for that.
* '''kernelParams''': Instead of using DHCP you could also configure a static IP, for example with kernel parameter <code>boot.kernelParams = [ "ip=10.25.0.2::10.25.0.1:255.255.255.0:myhost::none" ];</code>, where <code>10.25.0.2</code> is the client IP, <code>10.25.0.1</code> is the gateway IP. See [https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt the kernel documentation] for more information on the <code>ip=</code> parameter. When using DHCP, make sure your computer is always attached to the network and is able to get an IP adress, or the boot process will hang.
* '''kernelParams''':  
** When using a dynamic IP address with DHCP you might want to publish your hostname already in the initrd so it can be resolved in the local network: <code>boot.kernelParams = [ "ip=::::${config.networking.hostName}::dhcp" ];</code><ref>https://github.com/NixOS/nixpkgs/issues/63941#issuecomment-2628615604</ref> Note that when using DHCP, make sure your computer is always attached to the network and is able to get an IP adress, or the boot process will hang.
** You could also configure a static IP <code>boot.kernelParams = [ "ip=10.25.0.2::10.25.0.1:255.255.255.0:myhost::none" ];</code>, where <code>10.25.0.2</code> is the client IP, <code>10.25.0.1</code> is the gateway IP. See [https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt the kernel documentation] for more information on the <code>ip=</code> parameter.




The <code>shell</code> option is necessary to get a password prompt instead of a shell.
The <code>postCommands</code> option is necessary to get a password prompt instead of a shell.
If you omit it, you will get dropped into <code>/bin/ash</code>, and you will have to manually run <code>cryptsetup-askpass</code> to enter the password. Alternatively, the <code>shell</code> option can be set to <code>/bin/conspy</code> for passwords which expect stdin. This binary included by default, and provided by busybox.
If you omit it, you will get dropped into <code>/bin/ash</code>, and you will have to manually run <code>cryptsetup-askpass</code> to enter the password. Alternatively, the <code>boot.initrd.systemd.users.root.shell</code> option can be set to <code>/bin/conspy</code> for passwords which expect stdin. This binary included by default, and provided by busybox.


== Usage ==
== Usage ==
Line 73: Line 85:


Using systemd in initrd automatically continues the boot process after the target <code>/sysroot</code> is mounted.
Using systemd in initrd automatically continues the boot process after the target <code>/sysroot</code> is mounted.
=== Wireguard in initrd ===
Considering you've already enabled the ssh daemon, configured networking (for example with DHCP or static IP) and configured an unlocking command, following additional snippet will enable [[WireGuard]] connectivity to a remote peer while in initrd.<syntaxhighlight lang="nix">
boot.initrd.availableKernelModules = [ "r8169" "wireguard" ];
boot.initrd.systemd = {
  enable = true;
  network = {
    netdevs."30-wg-initrd" = {
      netdevConfig = {
        Kind = "wireguard";
        Name = "wg-initrd";
      };
      wireguardConfig = { PrivateKeyFile = "/etc/secrets/30-wg-initrd.key"; };
      wireguardPeers = [{
        AllowedIPs = [ "10.250.0.1/32" ];
        PublicKey = "wUE//Lwi8DZVIvAjIAtMoy+ku+hJ0w28H7ofySwAJRk=";
        Endpoint = "198.51.100.1:51821";
        PersistentKeepalive = 25;
      }];
    };
    networks."30-wg-initrd" = {
      name = "wg-initrd";
      addresses = [{ Address = "10.250.0.2/24"; }];
    };
  };
};
boot.initrd.secrets."/etc/secrets/30-wg-initrd.key" = "/etc/wireguard/private-key";
</syntaxhighlight>First generate a private und public key pair as mentioned in the WireGuard article. Reference the private key in <code>boot.initrd.secrets</code>, in this exmaple <code>/etc/wireguard/private-key</code>. Put the <code>PublicKey</code> of the remote peer into the <code>wireguardPeers</code> array.
Configure the IP addresses used by your initrd peer (<code>10.250.0.2</code>) and the remote peer (<code>10.250.0.1</code>). Also specify the IP and port of the remote peer in <code>Endpoint</code>, in our example <code>198.51.100.1:51821</code>. The remote peer also needs to know address configuration and the public key of the initrd peer.
Last but not least add the <code>wireguard</code> kernel module to <code>boot.initrd.availableKernelModules</code> beside the module required by your network device.


=== Tor in initrd ===
=== Tor in initrd ===


An example with an ssh server listening at a tor hidden service address can be found at [https://cgit.euer.krebsco.de/stockholm/tree/krebs/2configs/tor/initrd.nix?id=9919cb25912dfcc50881239f95494dd2f8e7b858 krebs/2configs/tor/initrd.nix in stockholm]
An example with an ssh server listening at a tor hidden service address can be found at [https://cgit.euer.krebsco.de/makefu/stockholm/src/commit/9b1008814e981dc01afe9ee7446322ad512c1d72/krebs/2configs/tor/initrd.nix krebs/2configs/tor/initrd.nix in stockholm]


==== Prepare the Onion ID ====
==== Prepare the Onion ID ====
Line 86: Line 130:
* <code>hs_ed25519_secret_key</code>
* <code>hs_ed25519_secret_key</code>


To create these files, you have to run tor once, with a dummy configuration.
To create these files:
 
$ nix-shell -p mkp224o --command "mkp224o-donna snow -n 1 -d ."
<pre>DataDirectory /tmp/my-dummy.tor/
set workdir: ./
SOCKSPort 127.0.0.1:10050 IsolateDestAddr
nixuum6flqthv6ar52j5e2ldulylfsfgezykeg37iy74kqowcp5gxfyd.onion
SOCKSPort 127.0.0.1:10063
The files you need are in the <code>*.onion</code> directory:
HiddenServiceDir /home/tony/tor/onion
$ ls *.onion
HiddenServicePort 1234 127.0.0.1:1234</pre>
hostname  hs_ed25519_public_key  hs_ed25519_secret_key
Let’s asume you created this file in <code>/home/tony/tor/tor.rc</code>.
 
Verify that everything is <code>tor.rc</code> awesome, by running <code>tor -f /home/tony/tor/tor.rc --verify-config</code>. If you don’t see any errors, just run <code>tor -f /home/tony/tor/tor.rc</code>.
 
You will get some output like this.
 
<pre>May 21 18:38:39.000 [notice] Bootstrapped 80% (ap_conn): Connecting to a relay to build circuits
May 21 18:38:39.000 [notice] Bootstrapped 85% (ap_conn_done): Connected to a relay to build circuits
May 21 18:38:39.000 [notice] Bootstrapped 89% (ap_handshake): Finishing handshake with a relay to build circuits
May 21 18:38:39.000 [notice] Bootstrapped 90% (ap_handshake_done): Handshake finished with a relay to build circuits
May 21 18:38:39.000 [notice] Bootstrapped 95% (circuit_create): Establishing a Tor circuit
May 21 18:38:40.000 [notice] Bootstrapped 100% (done): Done</pre>
Hit <code>Ctrl-C</code> and the files you need, should be in <code>/home/tony/tor/onion</code>.


==== Setup Tor ====
==== Setup Tor ====
Line 113: Line 144:
<syntaxhighlight lang="nix"># copy your onion folder
<syntaxhighlight lang="nix"># copy your onion folder
boot.initrd.secrets = {
boot.initrd.secrets = {
   "/etc/tor/onion/bootup"; = /home/tony/tor/onion; # maybe find a better spot to store this.
   "/etc/tor/onion/bootup" = /home/tony/tor/onion; # maybe find a better spot to store this.
};
};


Line 185: Line 216:
=== Enable Wifi in initrd ===
=== Enable Wifi in initrd ===
Following example configuration by [https://discourse.nixos.org/t/wireless-connection-within-initrd/38317/13 @loutr] enables wifi connections inside initrd. Replace interface name <code>wlp0s20f0u4</code> with the name of your wifi adapter. Depending on your wifi device, you might need to add different kernel modules.<syntaxhighlight lang="nix">
Following example configuration by [https://discourse.nixos.org/t/wireless-connection-within-initrd/38317/13 @loutr] enables wifi connections inside initrd. Replace interface name <code>wlp0s20f0u4</code> with the name of your wifi adapter. Depending on your wifi device, you might need to add different kernel modules.<syntaxhighlight lang="nix">
boot.initrd = {
{
  # crypto coprocessor and wifi modules
  boot.initrd = {
  availableKernelModules = [ "ccm" "ctr" "iwlmvm" "iwlwifi" ];
    # crypto coprocessor and wifi modules
    availableKernelModules = [
      "ccm"
      "ctr"
      "iwlmvm"
      "iwlwifi"
    ];


  systemd = {
    systemd = {
    enable = true;
      enable = true;


    packages = [ pkgs.wpa_supplicant ];
      packages = [ pkgs.wpa_supplicant ];
    initrdBin = [ pkgs.wpa_supplicant ];
      initrdBin = [ pkgs.wpa_supplicant ];
    targets.initrd.wants = [ "wpa_supplicant@wlp0s20f0u4.service" ];
      targets.initrd.wants = [ "wpa_supplicant@wlp0s20f0u4.service" ];


    # prevent WPA supplicant from requiring `sysinit.target`.
      # prevent WPA supplicant from requiring `sysinit.target`.
    services."wpa_supplicant@".unitConfig.DefaultDependencies = false;
      services."wpa_supplicant@".unitConfig.DefaultDependencies = false;


    users.root.shell = "/bin/systemd-tty-ask-password-agent";
      users.root.shell = "/bin/systemd-tty-ask-password-agent";


    network = {
      network = {
      enable = true;
      networks."10-wlan" = {
        matchConfig.Name = "wlp0s20f0u4";
        networkConfig.DHCP = "yes";
      };
      ssh = {
         enable = true;
         enable = true;
         port = 22;
         networks."10-wlan" = {
        hostKeys = [ "/etc/ssh/ssh_host_ed25519_key" ];
          matchConfig.Name = "wlp0s20f0u4";
         authorizedKeys = default.user.openssh.authorizedKeys.keys;
          DHCP = "yes";
         };
       };
       };
    };
    network.ssh = {
      enable = true;
      port = 22;
      hostKeys = [ "/etc/ssh/ssh_host_ed25519_key" ];
      authorizedKeys = default.user.openssh.authorizedKeys.keys;
     };
     };


     secrets."/etc/wpa_supplicant/wpa_supplicant-wlp0s20f0u4.conf" = /root/secrets/wpa_supplicant.conf;
     secrets."/etc/wpa_supplicant/wpa_supplicant-wlp0s20f0u4.conf" = /root/secrets/wpa_supplicant.conf;
   };
   };
</syntaxhighlight>The file <code>wpa_supplicat-wlp0s20f0u4.conf</code> is the wireless profile used by [[wpa_supplicant]] which will get copied into the initramfs.
}
</syntaxhighlight>The file <code>wpa_supplicant-wlp0s20f0u4.conf</code> is the wireless profile used by [[wpa_supplicant]] which will get copied into the initramfs.
[[Category:Server]]
[[Category:Server]]
[[Category:Cookbook]]
[[Category:Cookbook]]