Merge pull request #305742 from tomfitzhenry/ssh-no-pam

nixos/ssh: expose UsePAM and PrintMotd as options

authored by Thomas Gerbet and committed by GitHub ecd2d35b 7ff93499

+47 -17
+4 -4
nixos/modules/services/networking/ssh/sshd.nix
··· 346 violates the privacy of users and is not recommended. 347 ''; 348 }; 349 UseDns = mkOption { 350 type = types.bool; 351 # apply if cfg.useDns then "yes" else "no" ··· 489 {manpage}`sshd_config(5)` for details. 490 ''; 491 }; 492 }; 493 }); 494 }; ··· 622 623 networking.firewall.allowedTCPPorts = optionals cfg.openFirewall cfg.ports; 624 625 - security.pam.services.sshd = 626 { startSession = true; 627 showMotd = true; 628 unixAuth = cfg.settings.PasswordAuthentication; ··· 638 639 services.openssh.extraConfig = mkOrder 0 640 '' 641 - UsePAM yes 642 - 643 Banner ${if cfg.banner == null then "none" else pkgs.writeText "ssh_banner" cfg.banner} 644 645 AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} ··· 657 ${optionalString cfg.allowSFTP '' 658 Subsystem sftp ${cfg.sftpServerExecutable} ${concatStringsSep " " cfg.sftpFlags} 659 ''} 660 - PrintMotd no # handled by pam_motd 661 AuthorizedKeysFile ${toString cfg.authorizedKeysFiles} 662 ${optionalString (cfg.authorizedKeysCommand != "none") '' 663 AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
··· 346 violates the privacy of users and is not recommended. 347 ''; 348 }; 349 + UsePAM = mkEnableOption "PAM authentication" // { default = true; }; 350 UseDns = mkOption { 351 type = types.bool; 352 # apply if cfg.useDns then "yes" else "no" ··· 490 {manpage}`sshd_config(5)` for details. 491 ''; 492 }; 493 + # Disabled by default, since pam_motd handles this. 494 + PrintMotd = mkEnableOption "printing /etc/motd when a user logs in interactively"; 495 }; 496 }); 497 }; ··· 625 626 networking.firewall.allowedTCPPorts = optionals cfg.openFirewall cfg.ports; 627 628 + security.pam.services.sshd = lib.mkIf cfg.settings.UsePAM 629 { startSession = true; 630 showMotd = true; 631 unixAuth = cfg.settings.PasswordAuthentication; ··· 641 642 services.openssh.extraConfig = mkOrder 0 643 '' 644 Banner ${if cfg.banner == null then "none" else pkgs.writeText "ssh_banner" cfg.banner} 645 646 AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} ··· 658 ${optionalString cfg.allowSFTP '' 659 Subsystem sftp ${cfg.sftpServerExecutable} ${concatStringsSep " " cfg.sftpFlags} 660 ''} 661 AuthorizedKeysFile ${toString cfg.authorizedKeysFiles} 662 ${optionalString (cfg.authorizedKeysCommand != "none") '' 663 AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
+43 -13
nixos/tests/openssh.nix
··· 22 ]; 23 }; 24 25 server-lazy = 26 { ... }: 27 ··· 95 }; 96 }; 97 98 - server_allowedusers = 99 - { ... }: 100 - 101 { 102 - services.openssh = { enable = true; settings.AllowUsers = [ "alice" "bob" ]; }; 103 - users.groups = { alice = { }; bob = { }; carol = { }; }; 104 - users.users = { 105 - alice = { isNormalUser = true; group = "alice"; openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; }; 106 - bob = { isNormalUser = true; group = "bob"; openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; }; 107 - carol = { isNormalUser = true; group = "carol"; openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; }; 108 }; 109 }; 110 111 client = ··· 119 start_all() 120 121 server.wait_for_unit("sshd", timeout=30) 122 server_localhost_only.wait_for_unit("sshd", timeout=30) 123 server_match_rule.wait_for_unit("sshd", timeout=30) 124 125 server_lazy.wait_for_unit("sshd.socket", timeout=30) 126 server_localhost_only_lazy.wait_for_unit("sshd.socket", timeout=30) ··· 166 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 167 ) 168 client.succeed("chmod 600 privkey.snakeoil") 169 client.succeed( 170 - "ssh -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil root@192.168.2.4 true", 171 timeout=30 172 ) 173 ··· 198 ) 199 client.succeed("chmod 600 privkey.snakeoil") 200 client.succeed( 201 - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil alice@server_allowedusers true", 202 timeout=30 203 ) 204 client.succeed( 205 - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil bob@server_allowedusers true", 206 timeout=30 207 ) 208 client.fail( 209 - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil carol@server_allowedusers true", 210 timeout=30 211 ) 212 '';
··· 22 ]; 23 }; 24 25 + server-allowed-users = 26 + { ... }: 27 + 28 + { 29 + services.openssh = { enable = true; settings.AllowUsers = [ "alice" "bob" ]; }; 30 + users.groups = { alice = { }; bob = { }; carol = { }; }; 31 + users.users = { 32 + alice = { isNormalUser = true; group = "alice"; openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; }; 33 + bob = { isNormalUser = true; group = "bob"; openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; }; 34 + carol = { isNormalUser = true; group = "carol"; openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; }; 35 + }; 36 + }; 37 + 38 server-lazy = 39 { ... }: 40 ··· 108 }; 109 }; 110 111 + server-no-pam = 112 + { pkgs, ... }: 113 { 114 + programs.ssh.package = pkgs.opensshPackages.openssh.override { 115 + withPAM = false; 116 }; 117 + services.openssh = { 118 + enable = true; 119 + settings = { 120 + UsePAM = false; 121 + }; 122 + }; 123 + users.users.root.openssh.authorizedKeys.keys = [ 124 + snakeOilPublicKey 125 + ]; 126 }; 127 128 client = ··· 136 start_all() 137 138 server.wait_for_unit("sshd", timeout=30) 139 + server_allowed_users.wait_for_unit("sshd", timeout=30) 140 server_localhost_only.wait_for_unit("sshd", timeout=30) 141 server_match_rule.wait_for_unit("sshd", timeout=30) 142 + server_no_pam.wait_for_unit("sshd", timeout=30) 143 144 server_lazy.wait_for_unit("sshd.socket", timeout=30) 145 server_localhost_only_lazy.wait_for_unit("sshd.socket", timeout=30) ··· 185 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 186 ) 187 client.succeed("chmod 600 privkey.snakeoil") 188 + # The final segment in this IP is allocated according to the alphabetical order of machines in this test. 189 client.succeed( 190 + "ssh -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil root@192.168.2.5 true", 191 timeout=30 192 ) 193 ··· 218 ) 219 client.succeed("chmod 600 privkey.snakeoil") 220 client.succeed( 221 + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil alice@server-allowed-users true", 222 timeout=30 223 ) 224 client.succeed( 225 + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil bob@server-allowed-users true", 226 timeout=30 227 ) 228 client.fail( 229 + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil carol@server-allowed-users true", 230 + timeout=30 231 + ) 232 + 233 + with subtest("no-pam"): 234 + client.succeed( 235 + "cat ${snakeOilPrivateKey} > privkey.snakeoil" 236 + ) 237 + client.succeed("chmod 600 privkey.snakeoil") 238 + client.succeed( 239 + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-no-pam true", 240 timeout=30 241 ) 242 '';