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