diff options
Diffstat (limited to 'nixos/modules/services/networking/ssh/sshd.nix')
-rw-r--r-- | nixos/modules/services/networking/ssh/sshd.nix | 88 |
1 files changed, 63 insertions, 25 deletions
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index e4b29a0b909..b2740bd33b7 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -9,19 +9,13 @@ let nssModulesPath = config.system.nssModules.path; - permitRootLoginCheck = v: - v == "yes" || - v == "without-password" || - v == "forced-commands-only" || - v == "no"; - knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts); - knownHostsFile = pkgs.writeText "ssh_known_hosts" ( - flip concatMapStrings knownHosts (h: '' - ${concatStringsSep "," h.hostNames} ${if h.publicKey != null then h.publicKey else readFile h.publicKeyFile} - '') - ); + knownHostsText = flip (concatMapStringsSep "\n") knownHosts + (h: + concatStringsSep "," h.hostNames + " " + + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) + ); userOptions = { @@ -116,12 +110,9 @@ in permitRootLogin = mkOption { default = "without-password"; - type = types.addCheck types.str permitRootLoginCheck; + type = types.enum ["yes" "without-password" "forced-commands-only" "no"]; description = '' - Whether the root user can login using ssh. Valid values are - <literal>yes</literal>, <literal>without-password</literal>, - <literal>forced-commands-only</literal> or - <literal>no</literal>. + Whether the root user can login using ssh. ''; }; @@ -144,6 +135,36 @@ in ''; }; + listenAddresses = mkOption { + type = types.listOf types.optionSet; + default = []; + example = [ { addr = "192.168.3.1"; port = 22; } { addr = "0.0.0.0"; port = 64022; } ]; + description = '' + List of addresses and ports to listen on (ListenAddress directive + in config). If port is not specified for address sshd will listen + on all ports specified by <literal>ports</literal> option. + NOTE: this will override default listening on all local addresses and port 22. + NOTE: setting this option won't automatically enable given ports + in firewall configuration. + ''; + options = { + addr = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Host, IPv4 or IPv6 address to listen to. + ''; + }; + port = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Port to listen to. + ''; + }; + }; + }; + passwordAuthentication = mkOption { type = types.bool; default = true; @@ -165,12 +186,14 @@ in default = [ { path = "/etc/ssh/ssh_host_dsa_key"; type = "dsa"; - bits = 1024; } { path = "/etc/ssh/ssh_host_ecdsa_key"; type = "ecdsa"; bits = 521; } + { path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } ]; description = '' NixOS can automatically generate SSH host keys. This option @@ -224,7 +247,10 @@ in description = '' The public key data for the host. You can fetch a public key from a running SSH server with the <command>ssh-keyscan</command> - command. + command. The public key should not include any host names, only + the key type and the key itself. It is allowed to add several + lines here, each line will be treated as type/key pair and the + host names will be prepended to each line. ''; }; publicKeyFile = mkOption { @@ -234,7 +260,9 @@ in The path to the public key file for the host. The public key file is read at build time and saved in the Nix store. You can fetch a public key file from a running SSH server - with the <command>ssh-keyscan</command> command. + with the <command>ssh-keyscan</command> command. The content + of the file should follow the same format as described for + the <literal>publicKey</literal> option. ''; }; }; @@ -261,10 +289,10 @@ in }; environment.etc = authKeysFiles ++ [ - { source = "${pkgs.openssh}/etc/ssh/moduli"; + { source = "${cfgc.package}/etc/ssh/moduli"; target = "ssh/moduli"; } - { source = knownHostsFile; + { text = knownHostsText; target = "ssh/ssh_known_hosts"; } ]; @@ -278,7 +306,7 @@ in stopIfChanged = false; - path = [ pkgs.openssh pkgs.gawk ]; + path = [ cfgc.package pkgs.gawk ]; environment.LD_LIBRARY_PATH = nssModulesPath; @@ -288,14 +316,14 @@ in ${flip concatMapStrings cfg.hostKeys (k: '' if ! [ -f "${k.path}" ]; then - ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N "" + ssh-keygen -t "${k.type}" ${if k ? bits then "-b ${toString k.bits}" else ""} -f "${k.path}" -N "" fi '')} ''; serviceConfig = { ExecStart = - "${pkgs.openssh}/sbin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + + "${cfgc.package}/sbin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}"; KillMode = "process"; } // (if cfg.startWhenNeeded then { @@ -344,11 +372,17 @@ in UsePAM yes + UsePrivilegeSeparation sandbox + AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} ${concatMapStrings (port: '' Port ${toString port} '') cfg.ports} + ${concatMapStrings ({ port, addr }: '' + ListenAddress ${addr}${if port != null then ":" + toString port else ""} + '') cfg.listenAddresses} + ${optionalString cfgc.setXAuthLocation '' XAuthLocation ${pkgs.xorg.xauth}/bin/xauth ''} @@ -360,7 +394,7 @@ in ''} ${optionalString cfg.allowSFTP '' - Subsystem sftp ${pkgs.openssh}/libexec/sftp-server + Subsystem sftp ${cfgc.package}/libexec/sftp-server ''} PermitRootLogin ${cfg.permitRootLogin} @@ -383,6 +417,10 @@ in assertion = (data.publicKey == null && data.publicKeyFile != null) || (data.publicKey != null && data.publicKeyFile == null); message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; + }) + ++ flip map cfg.listenAddresses ({ addr, port }: { + assertion = addr != null; + message = "addr must be specified in each listenAddresses entry"; }); }; |