about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorMatthieu Coudron <teto@users.noreply.github.com>2023-01-15 16:32:46 +0100
committerGitHub <noreply@github.com>2023-01-15 16:32:46 +0100
commitcf10d7aef8ff9ca0e178e87981d9e4fd3018193c (patch)
tree633e4d0e9ab445d1675e2b002dd29689cdf5e01d /nixos
parent6dccdc458512abce8d19f74195bb20fdb067df50 (diff)
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
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/configuration/ssh.section.md2
-rw-r--r--nixos/doc/manual/from_md/configuration/ssh.section.xml2
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2305.section.xml18
-rw-r--r--nixos/doc/manual/release-notes/rl-2305.section.md2
-rw-r--r--nixos/modules/profiles/installation-device.nix2
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix128
-rw-r--r--nixos/modules/services/security/fail2ban.nix2
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix2
-rw-r--r--nixos/modules/virtualisation/azure-common.nix6
-rw-r--r--nixos/modules/virtualisation/brightbox-image.nix2
-rw-r--r--nixos/modules/virtualisation/cloudstack-config.nix2
-rw-r--r--nixos/modules/virtualisation/digital-ocean-config.nix2
-rw-r--r--nixos/modules/virtualisation/google-compute-config.nix4
-rw-r--r--nixos/modules/virtualisation/openstack-config.nix4
-rw-r--r--nixos/tests/borgbackup.nix6
-rw-r--r--nixos/tests/btrbk.nix6
-rw-r--r--nixos/tests/google-oslogin/server.nix4
-rw-r--r--nixos/tests/sourcehut.nix6
-rw-r--r--nixos/tests/turbovnc-headless-server.nix2
19 files changed, 124 insertions, 78 deletions
diff --git a/nixos/doc/manual/configuration/ssh.section.md b/nixos/doc/manual/configuration/ssh.section.md
index cba81eb43f49d..9e239a8481789 100644
--- a/nixos/doc/manual/configuration/ssh.section.md
+++ b/nixos/doc/manual/configuration/ssh.section.md
@@ -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:
diff --git a/nixos/doc/manual/from_md/configuration/ssh.section.xml b/nixos/doc/manual/from_md/configuration/ssh.section.xml
index a330457f51d63..e0d4031443ef9 100644
--- a/nixos/doc/manual/from_md/configuration/ssh.section.xml
+++ b/nixos/doc/manual/from_md/configuration/ssh.section.xml
@@ -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>
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml
index d6dea111b97b1..e1317621418d9 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml
@@ -326,6 +326,24 @@
       </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
           named <literal>mastodon-tootctl</literal> similar to
           <literal>nextcloud-occ</literal> which can be executed from
diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md
index beffe19c2ea7d..1620e98f3aa31 100644
--- a/nixos/doc/manual/release-notes/rl-2305.section.md
+++ b/nixos/doc/manual/release-notes/rl-2305.section.md
@@ -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
diff --git a/nixos/modules/profiles/installation-device.nix b/nixos/modules/profiles/installation-device.nix
index 4d9bd69666c09..980720691a437 100644
--- a/nixos/modules/profiles/installation-device.nix
+++ b/nixos/modules/profiles/installation-device.nix
@@ -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.
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index 37d7518ab3c4e..3a8640171b70b 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -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;
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index 8d923187941ce..6207f9dae971d 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -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}
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index 9751f5755f96d..e6c2c72339fd7 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -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;
diff --git a/nixos/modules/virtualisation/azure-common.nix b/nixos/modules/virtualisation/azure-common.nix
index dc7853b95032c..f29d368137ae0 100644
--- a/nixos/modules/virtualisation/azure-common.nix
+++ b/nixos/modules/virtualisation/azure-common.nix
@@ -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 "";
diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix
index 9641b693f1847..15f8fd6d8f7da 100644
--- a/nixos/modules/virtualisation/brightbox-image.nix
+++ b/nixos/modules/virtualisation/brightbox-image.nix
@@ -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 "";
diff --git a/nixos/modules/virtualisation/cloudstack-config.nix b/nixos/modules/virtualisation/cloudstack-config.nix
index 78afebdc5dd3a..7df3c9c613b42 100644
--- a/nixos/modules/virtualisation/cloudstack-config.nix
+++ b/nixos/modules/virtualisation/cloudstack-config.nix
@@ -21,7 +21,7 @@ with lib;
     # Allow root logins
     services.openssh = {
       enable = true;
-      permitRootLogin = "prohibit-password";
+      settings.PermitRootLogin = "prohibit-password";
     };
 
     # Cloud-init configuration.
diff --git a/nixos/modules/virtualisation/digital-ocean-config.nix b/nixos/modules/virtualisation/digital-ocean-config.nix
index 754bc1a518576..e004b7880aad0 100644
--- a/nixos/modules/virtualisation/digital-ocean-config.nix
+++ b/nixos/modules/virtualisation/digital-ocean-config.nix
@@ -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 = {
diff --git a/nixos/modules/virtualisation/google-compute-config.nix b/nixos/modules/virtualisation/google-compute-config.nix
index 44d2a589511f6..0bed0dc933e3a 100644
--- a/nixos/modules/virtualisation/google-compute-config.nix
+++ b/nixos/modules/virtualisation/google-compute-config.nix
@@ -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
diff --git a/nixos/modules/virtualisation/openstack-config.nix b/nixos/modules/virtualisation/openstack-config.nix
index af4f574661091..0ef7a3b501067 100644
--- a/nixos/modules/virtualisation/openstack-config.nix
+++ b/nixos/modules/virtualisation/openstack-config.nix
@@ -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";
diff --git a/nixos/tests/borgbackup.nix b/nixos/tests/borgbackup.nix
index 9afe4d537da44..4160e727f047b 100644
--- a/nixos/tests/borgbackup.nix
+++ b/nixos/tests/borgbackup.nix
@@ -117,8 +117,10 @@ in {
     server = { ... }: {
       services.openssh = {
         enable = true;
-        passwordAuthentication = false;
-        kbdInteractiveAuthentication = false;
+        settings = {
+          PasswordAuthentication = false;
+          KbdInteractiveAuthentication = false;
+        };
       };
 
       services.borgbackup.repos.repo1 = {
diff --git a/nixos/tests/btrbk.nix b/nixos/tests/btrbk.nix
index 9f34f7dfbe38f..5261321dfa2c5 100644
--- a/nixos/tests/btrbk.nix
+++ b/nixos/tests/btrbk.nix
@@ -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 ];
diff --git a/nixos/tests/google-oslogin/server.nix b/nixos/tests/google-oslogin/server.nix
index faf5e847d7e95..3df41155c92d4 100644
--- a/nixos/tests/google-oslogin/server.nix
+++ b/nixos/tests/google-oslogin/server.nix
@@ -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;
 
diff --git a/nixos/tests/sourcehut.nix b/nixos/tests/sourcehut.nix
index 9caa1bcd98f50..87e6d82bdd8f4 100644
--- a/nixos/tests/sourcehut.nix
+++ b/nixos/tests/sourcehut.nix
@@ -18,8 +18,10 @@ let
           # passwordless ssh server
           services.openssh = {
             enable = true;
-            permitRootLogin = "yes";
-            extraConfig = "PermitEmptyPasswords yes";
+            settings = {
+              PermitRootLogin = "yes";
+              PermitEmptyPasswords = true;
+            };
           };
 
           users = {
diff --git a/nixos/tests/turbovnc-headless-server.nix b/nixos/tests/turbovnc-headless-server.nix
index 1dbf9297c8131..a155f9f907b25 100644
--- a/nixos/tests/turbovnc-headless-server.nix
+++ b/nixos/tests/turbovnc-headless-server.nix
@@ -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;
   };