services.openssh: support freeform settings (#193757)

* services.openssh: support freeform settings

Keep "extraConfig" but introduces "settings".

Also renames several options

(mkRenamedOptionModule [ "services" "openssh" "kbdInteractiveAuthentication" ] [  "services" "openssh" "settings" "KbdInteractiveAuthentication" ])
(mkRenamedOptionModule [ "services" "openssh" "passwordAuthentication" ] [  "services" "openssh" "settings" "PasswordAuthentication" ])
(mkRenamedOptionModule [ "services" "openssh" "useDns" ] [  "services" "openssh" "settings" "UseDns" ])
(mkRenamedOptionModule [ "services" "openssh" "permitRootLogin" ] [  "services" "openssh" "settings" "PermitRootLogin" ])

* updated doc
* regen doc
This commit is contained in:
Matthieu Coudron 2023-01-15 16:32:46 +01:00 committed by GitHub
parent 6dccdc4585
commit cf10d7aef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 124 additions and 78 deletions

View File

@ -8,7 +8,7 @@ services.openssh.enable = true;
By default, root logins using a password are disallowed. They can be
disabled entirely by setting
[](#opt-services.openssh.permitRootLogin) to `"no"`.
[](#opt-services.openssh.settings.PermitRootLogin) to `"no"`.
You can declaratively specify authorised RSA/DSA public keys for a user
as follows:

View File

@ -9,7 +9,7 @@ services.openssh.enable = true;
<para>
By default, root logins using a password are disallowed. They can be
disabled entirely by setting
<xref linkend="opt-services.openssh.permitRootLogin" /> to
<xref linkend="opt-services.openssh.settings.PermitRootLogin" /> to
<literal>&quot;no&quot;</literal>.
</para>
<para>

View File

@ -324,6 +324,24 @@
<link linkend="opt-services.usbmuxd.package">services.usbmuxd.package</link>
</para>
</listitem>
<listitem>
<para>
A few openssh options have been moved from extraConfig to the
new freeform option <literal>settings</literal> and renamed as
follow:
<literal>services.openssh.kbdInteractiveAuthentication</literal>
to
<literal>services.openssh.settings.KbdInteractiveAuthentication</literal>,
<literal>services.openssh.passwordAuthentication</literal> to
<literal>services.openssh.settings.PasswordAuthentication</literal>,
<literal>services.openssh.useDns</literal> to
<literal>services.openssh.settings.UseDns</literal>,
<literal>services.openssh.permitRootLogin</literal> to
<literal>services.openssh.settings.PermitRootLogin</literal>,
<literal>services.openssh.logLevel</literal> to
<literal>services.openssh.settings.LogLevel</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>services.mastodon</literal> gained a tootctl wrapped

View File

@ -85,6 +85,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- The module `usbmuxd` now has the ability to change the package used by the daemon. In case you're experiencing issues with `usbmuxd` you can try an alternative program like `usbmuxd2`. Available as [services.usbmuxd.package](#opt-services.usbmuxd.package)
- A few openssh options have been moved from extraConfig to the new freeform option `settings` and renamed as follow: `services.openssh.kbdInteractiveAuthentication` to `services.openssh.settings.KbdInteractiveAuthentication`, `services.openssh.passwordAuthentication` to `services.openssh.settings.PasswordAuthentication`, `services.openssh.useDns` to `services.openssh.settings.UseDns`, `services.openssh.permitRootLogin` to `services.openssh.settings.PermitRootLogin`, `services.openssh.logLevel` to `services.openssh.settings.LogLevel`.
- `services.mastodon` gained a tootctl wrapped named `mastodon-tootctl` similar to `nextcloud-occ` which can be executed from any user and switches to the configured mastodon user with sudo and sources the environment variables.
- The `dnsmasq` service now takes configuration via the

View File

@ -72,7 +72,7 @@ with lib;
# mounting the storage in a different system.
services.openssh = {
enable = true;
permitRootLogin = "yes";
settings.PermitRootLogin = "yes";
};
# Enable wpa_supplicant, but don't start it by default.

View File

@ -12,8 +12,23 @@ let
then cfgc.package
else pkgs.buildPackages.openssh;
# reports boolean as yes / no
mkValueStringSshd = v:
if isInt v then toString v
else if isString v then v
else if true == v then "yes"
else if false == v then "no"
else throw "unsupported type ${typeOf v}: ${(lib.generators.toPretty {}) v}";
# dont use the "=" operator
settingsFormat = (pkgs.formats.keyValue {
mkKeyValue = lib.generators.mkKeyValueDefault {
mkValueString = mkValueStringSshd;
} " ";});
configFile = settingsFormat.generate "config" cfg.settings;
sshconf = pkgs.runCommand "sshd.conf-validated" { nativeBuildInputs = [ validationPackage ]; } ''
cat >$out <<EOL
cat ${configFile} - >$out <<EOL
${cfg.extraConfig}
EOL
@ -24,6 +39,7 @@ let
cfg = config.services.openssh;
cfgc = config.programs.ssh;
nssModulesPath = config.system.nssModules.path;
userOptions = {
@ -82,6 +98,12 @@ in
(mkAliasOptionModuleMD [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ])
(mkAliasOptionModuleMD [ "services" "openssh" "knownHosts" ] [ "programs" "ssh" "knownHosts" ])
(mkRenamedOptionModule [ "services" "openssh" "challengeResponseAuthentication" ] [ "services" "openssh" "kbdInteractiveAuthentication" ])
(mkRenamedOptionModule [ "services" "openssh" "kbdInteractiveAuthentication" ] [ "services" "openssh" "settings" "KbdInteractiveAuthentication" ])
(mkRenamedOptionModule [ "services" "openssh" "passwordAuthentication" ] [ "services" "openssh" "settings" "PasswordAuthentication" ])
(mkRenamedOptionModule [ "services" "openssh" "useDns" ] [ "services" "openssh" "settings" "UseDns" ])
(mkRenamedOptionModule [ "services" "openssh" "permitRootLogin" ] [ "services" "openssh" "settings" "PermitRootLogin" ])
(mkRenamedOptionModule [ "services" "openssh" "logLevel" ] [ "services" "openssh" "settings" "LogLevel" ])
];
###### interface
@ -145,14 +167,6 @@ in
'';
};
permitRootLogin = mkOption {
default = "prohibit-password";
type = types.enum ["yes" "without-password" "prohibit-password" "forced-commands-only" "no"];
description = lib.mdDoc ''
Whether the root user can login using ssh.
'';
};
gatewayPorts = mkOption {
type = types.str;
default = "no";
@ -210,22 +224,6 @@ in
'';
};
passwordAuthentication = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Specifies whether password authentication is allowed.
'';
};
kbdInteractiveAuthentication = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Specifies whether keyboard-interactive authentication is allowed.
'';
};
hostKeys = mkOption {
type = types.listOf types.attrs;
default =
@ -346,26 +344,58 @@ in
'';
};
logLevel = mkOption {
type = types.enum [ "QUIET" "FATAL" "ERROR" "INFO" "VERBOSE" "DEBUG" "DEBUG1" "DEBUG2" "DEBUG3" ];
default = "INFO"; # upstream default
description = lib.mdDoc ''
Gives the verbosity level that is used when logging messages from sshd(8). The possible values are:
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO. DEBUG and DEBUG1
are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. Logging with a DEBUG level
violates the privacy of users and is not recommended.
'';
};
useDns = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Specifies whether sshd(8) should look up the remote host name, and to check that the resolved host name for
the remote IP address maps back to the very same IP address.
If this option is set to no (the default) then only addresses and not host names may be used in
~/.ssh/authorized_keys from and sshd_config Match Host directives.
'';
settings = mkOption {
description = lib.mdDoc "Verbatim contents of {file}`sshd_config`.";
example = literalExpression ''{
UseDns true;
}'';
type = types.submodule ({name, ...}: {
freeformType = settingsFormat.type;
options = {
LogLevel = mkOption {
type = types.enum [ "QUIET" "FATAL" "ERROR" "INFO" "VERBOSE" "DEBUG" "DEBUG1" "DEBUG2" "DEBUG3" ];
default = "INFO"; # upstream default
description = lib.mdDoc ''
Gives the verbosity level that is used when logging messages from sshd(8). Logging with a DEBUG level
violates the privacy of users and is not recommended.
'';
};
UseDns = mkOption {
type = types.bool;
# apply if cfg.useDns then "yes" else "no"
default = false;
description = lib.mdDoc ''
Specifies whether sshd(8) should look up the remote host name, and to check that the resolved host name for
the remote IP address maps back to the very same IP address.
If this option is set to no (the default) then only addresses and not host names may be used in
~/.ssh/authorized_keys from and sshd_config Match Host directives.
'';
};
PasswordAuthentication = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Specifies whether password authentication is allowed.
'';
};
PermitRootLogin = mkOption {
default = "prohibit-password";
type = types.enum ["yes" "without-password" "prohibit-password" "forced-commands-only" "no"];
description = lib.mdDoc ''
Whether the root user can login using ssh.
'';
};
KbdInteractiveAuthentication = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Specifies whether keyboard-interactive authentication is allowed.
'';
};
};
});
};
extraConfig = mkOption {
@ -496,7 +526,7 @@ in
security.pam.services.sshd =
{ startSession = true;
showMotd = true;
unixAuth = cfg.passwordAuthentication;
unixAuth = cfg.settings.PasswordAuthentication;
};
# These values are merged with the ones defined externally, see:
@ -530,10 +560,7 @@ in
Subsystem sftp ${cfg.sftpServerExecutable} ${concatStringsSep " " cfg.sftpFlags}
''}
PermitRootLogin ${cfg.permitRootLogin}
GatewayPorts ${cfg.gatewayPorts}
PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"}
KbdInteractiveAuthentication ${if cfg.kbdInteractiveAuthentication then "yes" else "no"}
PrintMotd no # handled by pam_motd
@ -550,11 +577,6 @@ in
KexAlgorithms ${concatStringsSep "," cfg.kexAlgorithms}
Ciphers ${concatStringsSep "," cfg.ciphers}
MACs ${concatStringsSep "," cfg.macs}
LogLevel ${cfg.logLevel}
UseDNS ${if cfg.useDns then "yes" else "no"}
'';
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;

View File

@ -339,7 +339,7 @@ in
# Block SSH if there are too many failing connection attempts.
# Benefits from verbose sshd logging to observe failed login attempts,
# so we set that here unless the user overrode it.
services.openssh.logLevel = lib.mkDefault "VERBOSE";
services.openssh.settings.LogLevel = lib.mkDefault "VERBOSE";
services.fail2ban.jails.sshd = mkDefault ''
enabled = true
port = ${concatMapStringsSep "," (p: toString p) config.services.openssh.ports}

View File

@ -85,7 +85,7 @@ in
# Allow root logins only using the SSH key that the user specified
# at instance creation time.
services.openssh.enable = true;
services.openssh.permitRootLogin = "prohibit-password";
services.openssh.settings.PermitRootLogin = "prohibit-password";
# Enable the serial console on ttyS0
systemd.services."serial-getty@ttyS0".enable = true;

View File

@ -30,10 +30,8 @@ with lib;
# Allow root logins only using the SSH key that the user specified
# at instance creation time, ping client connections to avoid timeouts
services.openssh.enable = true;
services.openssh.permitRootLogin = "prohibit-password";
services.openssh.extraConfig = ''
ClientAliveInterval 180
'';
services.openssh.settings.PermitRootLogin = "prohibit-password";
services.openssh.settings.ClientAliveInterval = 180;
# Force getting the hostname from Azure
networking.hostName = mkDefault "";

View File

@ -103,7 +103,7 @@ in
# Allow root logins only using the SSH key that the user specified
# at instance creation time.
services.openssh.enable = true;
services.openssh.permitRootLogin = "prohibit-password";
services.openssh.settings.PermitRootLogin = "prohibit-password";
# Force getting the hostname from Google Compute.
networking.hostName = mkDefault "";

View File

@ -21,7 +21,7 @@ with lib;
# Allow root logins
services.openssh = {
enable = true;
permitRootLogin = "prohibit-password";
settings.PermitRootLogin = "prohibit-password";
};
# Cloud-init configuration.

View File

@ -49,7 +49,7 @@ with lib;
};
services.openssh = {
enable = mkDefault true;
passwordAuthentication = mkDefault false;
settings.PasswordAuthentication = mkDefault false;
};
services.do-agent.enable = mkDefault true;
networking = {

View File

@ -29,8 +29,8 @@ with lib;
# Allow root logins only using SSH keys
# and disable password authentication in general
services.openssh.enable = true;
services.openssh.permitRootLogin = "prohibit-password";
services.openssh.passwordAuthentication = mkDefault false;
services.openssh.settings.PermitRootLogin = "prohibit-password";
services.openssh.settings.PasswordAuthentication = mkDefault false;
# enable OS Login. This also requires setting enable-oslogin=TRUE metadata on
# instance or project level

View File

@ -59,8 +59,8 @@ in
# Allow root logins
services.openssh = {
enable = true;
permitRootLogin = "prohibit-password";
passwordAuthentication = mkDefault false;
settings.PermitRootLogin = "prohibit-password";
settings.PasswordAuthentication = mkDefault false;
};
users.users.root.initialPassword = "foobar";

View File

@ -117,8 +117,10 @@ in {
server = { ... }: {
services.openssh = {
enable = true;
passwordAuthentication = false;
kbdInteractiveAuthentication = false;
settings = {
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
};
};
services.borgbackup.repos.repo1 = {

View File

@ -52,8 +52,10 @@ import ./make-test-python.nix ({ pkgs, ... }:
environment.systemPackages = with pkgs; [ btrfs-progs ];
services.openssh = {
enable = true;
passwordAuthentication = false;
kbdInteractiveAuthentication = false;
settings = {
KbdInteractiveAuthentication = false;
PasswordAuthentication = false;
};
};
services.btrbk = {
extraPackages = [ pkgs.lz4 ];

View File

@ -17,8 +17,8 @@ in {
};
services.openssh.enable = true;
services.openssh.kbdInteractiveAuthentication = false;
services.openssh.passwordAuthentication = false;
services.openssh.settings.KbdInteractiveAuthentication = false;
services.openssh.settings.PasswordAuthentication = false;
security.googleOsLogin.enable = true;

View File

@ -18,8 +18,10 @@ let
# passwordless ssh server
services.openssh = {
enable = true;
permitRootLogin = "yes";
extraConfig = "PermitEmptyPasswords yes";
settings = {
PermitRootLogin = "yes";
PermitEmptyPasswords = true;
};
};
users = {

View File

@ -26,7 +26,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
# So that we can ssh into the VM, see e.g.
# http://blog.patapon.info/nixos-local-vm/#accessing-the-vm-with-ssh
services.openssh.enable = true;
services.openssh.permitRootLogin = "yes";
services.openssh.settings.PermitRootLogin = "yes";
users.extraUsers.root.password = "";
users.mutableUsers = false;
};