aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/system/boot/initrd-ssh.nix')
-rw-r--r--nixpkgs/nixos/modules/system/boot/initrd-ssh.nix178
1 files changed, 124 insertions, 54 deletions
diff --git a/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix b/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix
index 2d3e3b05c98..5a334e69056 100644
--- a/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix
@@ -10,19 +10,21 @@ in
{
- options = {
-
- boot.initrd.network.ssh.enable = mkOption {
+ options.boot.initrd.network.ssh = {
+ enable = mkOption {
type = types.bool;
default = false;
description = ''
Start SSH service during initrd boot. It can be used to debug failing
boot on a remote server, enter pasphrase for an encrypted partition etc.
Service is killed when stage-1 boot is finished.
+
+ The sshd configuration is largely inherited from
+ <option>services.openssh</option>.
'';
};
- boot.initrd.network.ssh.port = mkOption {
+ port = mkOption {
type = types.int;
default = 22;
description = ''
@@ -30,7 +32,7 @@ in
'';
};
- boot.initrd.network.ssh.shell = mkOption {
+ shell = mkOption {
type = types.str;
default = "/bin/ash";
description = ''
@@ -38,95 +40,163 @@ in
'';
};
- boot.initrd.network.ssh.hostRSAKey = mkOption {
- type = types.nullOr types.path;
- default = null;
- description = ''
- RSA SSH private key file in the Dropbear format.
-
- WARNING: Unless your bootloader supports initrd secrets, this key is
- contained insecurely in the global Nix store. Do NOT use your regular
- SSH host private keys for this purpose or you'll expose them to
- regular users!
- '';
- };
-
- boot.initrd.network.ssh.hostDSSKey = mkOption {
- type = types.nullOr types.path;
- default = null;
+ hostKeys = mkOption {
+ type = types.listOf (types.either types.str types.path);
+ default = [];
+ example = [
+ "/etc/secrets/initrd/ssh_host_rsa_key"
+ "/etc/secrets/initrd/ssh_host_ed25519_key"
+ ];
description = ''
- DSS SSH private key file in the Dropbear format.
-
- WARNING: Unless your bootloader supports initrd secrets, this key is
- contained insecurely in the global Nix store. Do NOT use your regular
- SSH host private keys for this purpose or you'll expose them to
- regular users!
+ Specify SSH host keys to import into the initrd.
+
+ To generate keys, use
+ <citerefentry><refentrytitle>ssh-keygen</refentrytitle><manvolnum>1</manvolnum></citerefentry>:
+
+ <screen>
+ <prompt># </prompt>ssh-keygen -t rsa -N "" -f /etc/secrets/initrd/ssh_host_rsa_key
+ <prompt># </prompt>ssh-keygen -t ed25519 -N "" -f /etc/secrets/initrd/ssh_host_ed_25519_key
+ </screen>
+
+ <warning>
+ <para>
+ Unless your bootloader supports initrd secrets, these keys
+ are stored insecurely in the global Nix store. Do NOT use
+ your regular SSH host private keys for this purpose or
+ you'll expose them to regular users!
+ </para>
+ <para>
+ Additionally, even if your initrd supports secrets, if
+ you're using initrd SSH to unlock an encrypted disk then
+ using your regular host keys exposes the private keys on
+ your unencrypted boot partition.
+ </para>
+ </warning>
'';
};
- boot.initrd.network.ssh.hostECDSAKey = mkOption {
- type = types.nullOr types.path;
- default = null;
- description = ''
- ECDSA SSH private key file in the Dropbear format.
-
- WARNING: Unless your bootloader supports initrd secrets, this key is
- contained insecurely in the global Nix store. Do NOT use your regular
- SSH host private keys for this purpose or you'll expose them to
- regular users!
- '';
- };
-
- boot.initrd.network.ssh.authorizedKeys = mkOption {
+ authorizedKeys = mkOption {
type = types.listOf types.str;
default = config.users.users.root.openssh.authorizedKeys.keys;
+ defaultText = "config.users.users.root.openssh.authorizedKeys.keys";
description = ''
Authorized keys for the root user on initrd.
- Note that Dropbear doesn't support OpenSSH's Ed25519 key type.
'';
};
-
};
- config = mkIf (config.boot.initrd.network.enable && cfg.enable) {
+ imports =
+ map (opt: mkRemovedOptionModule ([ "boot" "initrd" "network" "ssh" ] ++ [ opt ]) ''
+ The initrd SSH functionality now uses OpenSSH rather than Dropbear.
+
+ If you want to keep your existing initrd SSH host keys, convert them with
+ $ dropbearconvert dropbear openssh dropbear_host_$type_key ssh_host_$type_key
+ and then set options.boot.initrd.network.ssh.hostKeys.
+ '') [ "hostRSAKey" "hostDSSKey" "hostECDSAKey" ];
+
+ config = let
+ # Nix complains if you include a store hash in initrd path names, so
+ # as an awful hack we drop the first character of the hash.
+ initrdKeyPath = path: if isString path
+ then path
+ else let name = builtins.baseNameOf path; in
+ builtins.unsafeDiscardStringContext ("/etc/ssh/" +
+ substring 1 (stringLength name) name);
+
+ sshdCfg = config.services.openssh;
+
+ sshdConfig = ''
+ Port ${toString cfg.port}
+
+ PasswordAuthentication no
+ ChallengeResponseAuthentication no
+
+ ${flip concatMapStrings cfg.hostKeys (path: ''
+ HostKey ${initrdKeyPath path}
+ '')}
+
+ KexAlgorithms ${concatStringsSep "," sshdCfg.kexAlgorithms}
+ Ciphers ${concatStringsSep "," sshdCfg.ciphers}
+ MACs ${concatStringsSep "," sshdCfg.macs}
+
+ LogLevel ${sshdCfg.logLevel}
+
+ ${if sshdCfg.useDns then ''
+ UseDNS yes
+ '' else ''
+ UseDNS no
+ ''}
+ '';
+ in mkIf (config.boot.initrd.network.enable && cfg.enable) {
assertions = [
- { assertion = cfg.authorizedKeys != [];
+ {
+ assertion = cfg.authorizedKeys != [];
message = "You should specify at least one authorized key for initrd SSH";
}
+
+ {
+ assertion = cfg.hostKeys != [];
+ message = ''
+ You must now pre-generate the host keys for initrd SSH.
+ See the boot.initrd.network.ssh.hostKeys documentation
+ for instructions.
+ '';
+ }
];
boot.initrd.extraUtilsCommands = ''
- copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
+ copy_bin_and_libs ${pkgs.openssh}/bin/sshd
cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib
'';
boot.initrd.extraUtilsCommandsTest = ''
- $out/bin/dropbear -V
+ # sshd requires a host key to check config, so we pass in the test's
+ echo -n ${escapeShellArg sshdConfig} |
+ $out/bin/sshd -t -f /dev/stdin \
+ -h ${../../../tests/initrd-network-ssh/ssh_host_ed25519_key}
'';
boot.initrd.network.postCommands = ''
echo '${cfg.shell}' > /etc/shells
echo 'root:x:0:0:root:/root:${cfg.shell}' > /etc/passwd
+ echo 'sshd:x:1:1:sshd:/var/empty:/bin/nologin' >> /etc/passwd
echo 'passwd: files' > /etc/nsswitch.conf
- mkdir -p /var/log
+ mkdir -p /var/log /var/empty
touch /var/log/lastlog
- mkdir -p /etc/dropbear
+ mkdir -p /etc/ssh
+ echo -n ${escapeShellArg sshdConfig} > /etc/ssh/sshd_config
+
+ echo "export PATH=$PATH" >> /etc/profile
+ echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> /etc/profile
mkdir -p /root/.ssh
${concatStrings (map (key: ''
echo ${escapeShellArg key} >> /root/.ssh/authorized_keys
'') cfg.authorizedKeys)}
- dropbear -s -j -k -E -p ${toString cfg.port} ${optionalString (cfg.hostRSAKey == null && cfg.hostDSSKey == null && cfg.hostECDSAKey == null) "-R"}
+ ${flip concatMapStrings cfg.hostKeys (path: ''
+ # keys from Nix store are world-readable, which sshd doesn't like
+ chmod 0600 "${initrdKeyPath path}"
+ '')}
+
+ /bin/sshd -e
'';
- boot.initrd.secrets =
- (optionalAttrs (cfg.hostRSAKey != null) { "/etc/dropbear/dropbear_rsa_host_key" = cfg.hostRSAKey; }) //
- (optionalAttrs (cfg.hostDSSKey != null) { "/etc/dropbear/dropbear_dss_host_key" = cfg.hostDSSKey; }) //
- (optionalAttrs (cfg.hostECDSAKey != null) { "/etc/dropbear/dropbear_ecdsa_host_key" = cfg.hostECDSAKey; });
+ boot.initrd.postMountCommands = ''
+ # Stop sshd cleanly before stage 2.
+ #
+ # If you want to keep it around to debug post-mount SSH issues,
+ # run `touch /.keep_sshd` (either from an SSH session or in
+ # another initrd hook like preDeviceCommands).
+ if ! [ -e /.keep_sshd ]; then
+ pkill -x sshd
+ fi
+ '';
+ boot.initrd.secrets = listToAttrs
+ (map (path: nameValuePair (initrdKeyPath path) path) cfg.hostKeys);
};
}