at 25.11-pre 11 kB view raw
1import ./make-test-python.nix ( 2 { pkgs, ... }: 3 4 let 5 inherit (import ./ssh-keys.nix pkgs) 6 snakeOilPrivateKey 7 snakeOilPublicKey 8 snakeOilEd25519PrivateKey 9 snakeOilEd25519PublicKey 10 ; 11 in 12 { 13 name = "openssh"; 14 meta = with pkgs.lib.maintainers; { 15 maintainers = [ aszlig ]; 16 }; 17 18 nodes = { 19 20 server = 21 { ... }: 22 23 { 24 services.openssh.enable = true; 25 security.pam.services.sshd.limits = [ 26 { 27 domain = "*"; 28 item = "memlock"; 29 type = "-"; 30 value = 1024; 31 } 32 ]; 33 users.users.root.openssh.authorizedKeys.keys = [ 34 snakeOilPublicKey 35 ]; 36 }; 37 38 server-allowed-users = 39 { ... }: 40 41 { 42 services.openssh = { 43 enable = true; 44 settings.AllowUsers = [ 45 "alice" 46 "bob" 47 ]; 48 }; 49 users.groups = { 50 alice = { }; 51 bob = { }; 52 carol = { }; 53 }; 54 users.users = { 55 alice = { 56 isNormalUser = true; 57 group = "alice"; 58 openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; 59 }; 60 bob = { 61 isNormalUser = true; 62 group = "bob"; 63 openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; 64 }; 65 carol = { 66 isNormalUser = true; 67 group = "carol"; 68 openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; 69 }; 70 }; 71 }; 72 73 server-lazy = 74 { ... }: 75 76 { 77 services.openssh = { 78 enable = true; 79 startWhenNeeded = true; 80 }; 81 security.pam.services.sshd.limits = [ 82 { 83 domain = "*"; 84 item = "memlock"; 85 type = "-"; 86 value = 1024; 87 } 88 ]; 89 users.users.root.openssh.authorizedKeys.keys = [ 90 snakeOilPublicKey 91 ]; 92 }; 93 94 server-lazy-socket = { 95 virtualisation.vlans = [ 96 1 97 2 98 ]; 99 services.openssh = { 100 enable = true; 101 startWhenNeeded = true; 102 ports = [ 2222 ]; 103 listenAddresses = [ { addr = "0.0.0.0"; } ]; 104 }; 105 users.users.root.openssh.authorizedKeys.keys = [ 106 snakeOilPublicKey 107 ]; 108 }; 109 110 server-localhost-only = 111 { ... }: 112 113 { 114 services.openssh = { 115 enable = true; 116 listenAddresses = [ 117 { 118 addr = "127.0.0.1"; 119 port = 22; 120 } 121 ]; 122 }; 123 }; 124 125 server-localhost-only-lazy = 126 { ... }: 127 128 { 129 services.openssh = { 130 enable = true; 131 startWhenNeeded = true; 132 listenAddresses = [ 133 { 134 addr = "127.0.0.1"; 135 port = 22; 136 } 137 ]; 138 }; 139 }; 140 141 server-match-rule = 142 { ... }: 143 144 { 145 services.openssh = { 146 enable = true; 147 listenAddresses = [ 148 { 149 addr = "127.0.0.1"; 150 port = 22; 151 } 152 { 153 addr = "[::]"; 154 port = 22; 155 } 156 ]; 157 extraConfig = '' 158 # Combined test for two (predictable) Match criterias 159 Match LocalAddress 127.0.0.1 LocalPort 22 160 PermitRootLogin yes 161 162 # Separate tests for Match criterias 163 Match User root 164 PermitRootLogin yes 165 Match Group root 166 PermitRootLogin yes 167 Match Host nohost.example 168 PermitRootLogin yes 169 Match LocalAddress 127.0.0.1 170 PermitRootLogin yes 171 Match LocalPort 22 172 PermitRootLogin yes 173 Match RDomain nohost.example 174 PermitRootLogin yes 175 Match Address 127.0.0.1 176 PermitRootLogin yes 177 ''; 178 }; 179 }; 180 181 server-no-openssl = 182 { ... }: 183 { 184 services.openssh = { 185 enable = true; 186 package = pkgs.opensshPackages.openssh.override { 187 linkOpenssl = false; 188 }; 189 hostKeys = [ 190 { 191 type = "ed25519"; 192 path = "/etc/ssh/ssh_host_ed25519_key"; 193 } 194 ]; 195 settings = { 196 # Since this test is against an OpenSSH-without-OpenSSL, 197 # we have to override NixOS's defaults ciphers (which require OpenSSL) 198 # and instead set these to null, which will mean OpenSSH uses its defaults. 199 # Expectedly, OpenSSH's defaults don't require OpenSSL when it's compiled 200 # without OpenSSL. 201 Ciphers = null; 202 KexAlgorithms = null; 203 Macs = null; 204 }; 205 }; 206 users.users.root.openssh.authorizedKeys.keys = [ 207 snakeOilEd25519PublicKey 208 ]; 209 }; 210 211 server-no-pam = 212 { pkgs, ... }: 213 { 214 services.openssh = { 215 enable = true; 216 package = pkgs.opensshPackages.openssh.override { 217 withPAM = false; 218 }; 219 settings = { 220 UsePAM = false; 221 }; 222 }; 223 users.users.root.openssh.authorizedKeys.keys = [ 224 snakeOilPublicKey 225 ]; 226 }; 227 228 client = 229 { ... }: 230 { 231 virtualisation.vlans = [ 232 1 233 2 234 ]; 235 }; 236 237 }; 238 239 testScript = '' 240 start_all() 241 242 server.wait_for_unit("sshd", timeout=30) 243 server_allowed_users.wait_for_unit("sshd", timeout=30) 244 server_localhost_only.wait_for_unit("sshd", timeout=30) 245 server_match_rule.wait_for_unit("sshd", timeout=30) 246 server_no_openssl.wait_for_unit("sshd", timeout=30) 247 server_no_pam.wait_for_unit("sshd", timeout=30) 248 249 server_lazy.wait_for_unit("sshd.socket", timeout=30) 250 server_localhost_only_lazy.wait_for_unit("sshd.socket", timeout=30) 251 server_lazy_socket.wait_for_unit("sshd.socket", timeout=30) 252 253 with subtest("manual-authkey"): 254 client.succeed( 255 '${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N ""' 256 ) 257 public_key = client.succeed( 258 "${pkgs.openssh}/bin/ssh-keygen -y -f /root/.ssh/id_ed25519" 259 ) 260 public_key = public_key.strip() 261 client.succeed("chmod 600 /root/.ssh/id_ed25519") 262 263 server.succeed("echo '{}' > /root/.ssh/authorized_keys".format(public_key)) 264 server_lazy.succeed("echo '{}' > /root/.ssh/authorized_keys".format(public_key)) 265 266 client.wait_for_unit("network.target") 267 client.succeed( 268 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world' >&2", 269 timeout=30 270 ) 271 client.succeed( 272 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'ulimit -l' | grep 1024", 273 timeout=30 274 ) 275 276 client.succeed( 277 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server-lazy 'echo hello world' >&2", 278 timeout=30 279 ) 280 client.succeed( 281 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server-lazy 'ulimit -l' | grep 1024", 282 timeout=30 283 ) 284 285 with subtest("socket activation on a non-standard port"): 286 client.succeed( 287 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 288 ) 289 client.succeed("chmod 600 privkey.snakeoil") 290 # The final segment in this IP is allocated according to the alphabetical order of machines in this test. 291 client.succeed( 292 "ssh -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil root@192.168.2.5 true", 293 timeout=30 294 ) 295 296 with subtest("configured-authkey"): 297 client.succeed( 298 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 299 ) 300 client.succeed("chmod 600 privkey.snakeoil") 301 client.succeed( 302 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server true", 303 timeout=30 304 ) 305 client.succeed( 306 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-lazy true", 307 timeout=30 308 ) 309 310 with subtest("localhost-only"): 311 server_localhost_only.succeed("ss -nlt | grep '127.0.0.1:22'") 312 server_localhost_only_lazy.succeed("ss -nlt | grep '127.0.0.1:22'") 313 314 with subtest("match-rules"): 315 server_match_rule.succeed("ss -nlt | grep '127.0.0.1:22'") 316 317 with subtest("allowed-users"): 318 client.succeed( 319 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 320 ) 321 client.succeed("chmod 600 privkey.snakeoil") 322 client.succeed( 323 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil alice@server-allowed-users true", 324 timeout=30 325 ) 326 client.succeed( 327 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil bob@server-allowed-users true", 328 timeout=30 329 ) 330 client.fail( 331 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil carol@server-allowed-users true", 332 timeout=30 333 ) 334 335 with subtest("no-openssl"): 336 client.succeed( 337 "cat ${snakeOilEd25519PrivateKey} > privkey.snakeoil" 338 ) 339 client.succeed("chmod 600 privkey.snakeoil") 340 client.succeed( 341 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-no-openssl true", 342 timeout=30 343 ) 344 345 with subtest("no-pam"): 346 client.succeed( 347 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 348 ) 349 client.succeed("chmod 600 privkey.snakeoil") 350 client.succeed( 351 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-no-pam true", 352 timeout=30 353 ) 354 355 # None of the per-connection units should have failed. 356 server_lazy.fail("systemctl is-failed 'sshd@*.service'") 357 ''; 358 } 359)