at 24.11-pre 9.2 kB view raw
1import ./make-test-python.nix ({ pkgs, ... }: 2 3let inherit (import ./ssh-keys.nix pkgs) 4 snakeOilPrivateKey snakeOilPublicKey snakeOilEd25519PrivateKey snakeOilEd25519PublicKey; 5in { 6 name = "openssh"; 7 meta = with pkgs.lib.maintainers; { 8 maintainers = [ aszlig ]; 9 }; 10 11 nodes = { 12 13 server = 14 { ... }: 15 16 { 17 services.openssh.enable = true; 18 security.pam.services.sshd.limits = 19 [ { domain = "*"; item = "memlock"; type = "-"; value = 1024; } ]; 20 users.users.root.openssh.authorizedKeys.keys = [ 21 snakeOilPublicKey 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 41 { 42 services.openssh = { enable = true; startWhenNeeded = true; }; 43 security.pam.services.sshd.limits = 44 [ { domain = "*"; item = "memlock"; type = "-"; value = 1024; } ]; 45 users.users.root.openssh.authorizedKeys.keys = [ 46 snakeOilPublicKey 47 ]; 48 }; 49 50 server-lazy-socket = { 51 virtualisation.vlans = [ 1 2 ]; 52 services.openssh = { 53 enable = true; 54 startWhenNeeded = true; 55 ports = [ 2222 ]; 56 listenAddresses = [ { addr = "0.0.0.0"; } ]; 57 }; 58 users.users.root.openssh.authorizedKeys.keys = [ 59 snakeOilPublicKey 60 ]; 61 }; 62 63 server-localhost-only = 64 { ... }: 65 66 { 67 services.openssh = { 68 enable = true; listenAddresses = [ { addr = "127.0.0.1"; port = 22; } ]; 69 }; 70 }; 71 72 server-localhost-only-lazy = 73 { ... }: 74 75 { 76 services.openssh = { 77 enable = true; startWhenNeeded = true; listenAddresses = [ { addr = "127.0.0.1"; port = 22; } ]; 78 }; 79 }; 80 81 server-match-rule = 82 { ... }: 83 84 { 85 services.openssh = { 86 enable = true; listenAddresses = [ { addr = "127.0.0.1"; port = 22; } { addr = "[::]"; port = 22; } ]; 87 extraConfig = '' 88 # Combined test for two (predictable) Match criterias 89 Match LocalAddress 127.0.0.1 LocalPort 22 90 PermitRootLogin yes 91 92 # Separate tests for Match criterias 93 Match User root 94 PermitRootLogin yes 95 Match Group root 96 PermitRootLogin yes 97 Match Host nohost.example 98 PermitRootLogin yes 99 Match LocalAddress 127.0.0.1 100 PermitRootLogin yes 101 Match LocalPort 22 102 PermitRootLogin yes 103 Match RDomain nohost.example 104 PermitRootLogin yes 105 Match Address 127.0.0.1 106 PermitRootLogin yes 107 ''; 108 }; 109 }; 110 111 server-no-openssl = 112 { ... }: 113 { 114 programs.ssh.package = pkgs.opensshPackages.openssh.override { 115 linkOpenssl = false; 116 }; 117 services.openssh = { 118 enable = true; 119 hostKeys = [ 120 { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; } 121 ]; 122 settings = { 123 # Must not specify the OpenSSL provided algorithms. 124 Ciphers = [ "chacha20-poly1305@openssh.com" ]; 125 KexAlgorithms = [ 126 "curve25519-sha256" 127 "curve25519-sha256@libssh.org" 128 ]; 129 }; 130 }; 131 users.users.root.openssh.authorizedKeys.keys = [ 132 snakeOilEd25519PublicKey 133 ]; 134 }; 135 136 server-no-pam = 137 { pkgs, ... }: 138 { 139 programs.ssh.package = pkgs.opensshPackages.openssh.override { 140 withPAM = false; 141 }; 142 services.openssh = { 143 enable = true; 144 settings = { 145 UsePAM = false; 146 }; 147 }; 148 users.users.root.openssh.authorizedKeys.keys = [ 149 snakeOilPublicKey 150 ]; 151 }; 152 153 client = 154 { ... }: { 155 virtualisation.vlans = [ 1 2 ]; 156 }; 157 158 }; 159 160 testScript = '' 161 start_all() 162 163 server.wait_for_unit("sshd", timeout=30) 164 server_allowed_users.wait_for_unit("sshd", timeout=30) 165 server_localhost_only.wait_for_unit("sshd", timeout=30) 166 server_match_rule.wait_for_unit("sshd", timeout=30) 167 server_no_openssl.wait_for_unit("sshd", timeout=30) 168 server_no_pam.wait_for_unit("sshd", timeout=30) 169 170 server_lazy.wait_for_unit("sshd.socket", timeout=30) 171 server_localhost_only_lazy.wait_for_unit("sshd.socket", timeout=30) 172 server_lazy_socket.wait_for_unit("sshd.socket", timeout=30) 173 174 with subtest("manual-authkey"): 175 client.succeed("mkdir -m 700 /root/.ssh") 176 client.succeed( 177 '${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N ""' 178 ) 179 public_key = client.succeed( 180 "${pkgs.openssh}/bin/ssh-keygen -y -f /root/.ssh/id_ed25519" 181 ) 182 public_key = public_key.strip() 183 client.succeed("chmod 600 /root/.ssh/id_ed25519") 184 185 server.succeed("mkdir -m 700 /root/.ssh") 186 server.succeed("echo '{}' > /root/.ssh/authorized_keys".format(public_key)) 187 server_lazy.succeed("mkdir -m 700 /root/.ssh") 188 server_lazy.succeed("echo '{}' > /root/.ssh/authorized_keys".format(public_key)) 189 190 client.wait_for_unit("network.target") 191 client.succeed( 192 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world' >&2", 193 timeout=30 194 ) 195 client.succeed( 196 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'ulimit -l' | grep 1024", 197 timeout=30 198 ) 199 200 client.succeed( 201 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server-lazy 'echo hello world' >&2", 202 timeout=30 203 ) 204 client.succeed( 205 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server-lazy 'ulimit -l' | grep 1024", 206 timeout=30 207 ) 208 209 with subtest("socket activation on a non-standard port"): 210 client.succeed( 211 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 212 ) 213 client.succeed("chmod 600 privkey.snakeoil") 214 # The final segment in this IP is allocated according to the alphabetical order of machines in this test. 215 client.succeed( 216 "ssh -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil root@192.168.2.5 true", 217 timeout=30 218 ) 219 220 with subtest("configured-authkey"): 221 client.succeed( 222 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 223 ) 224 client.succeed("chmod 600 privkey.snakeoil") 225 client.succeed( 226 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server true", 227 timeout=30 228 ) 229 client.succeed( 230 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-lazy true", 231 timeout=30 232 ) 233 234 with subtest("localhost-only"): 235 server_localhost_only.succeed("ss -nlt | grep '127.0.0.1:22'") 236 server_localhost_only_lazy.succeed("ss -nlt | grep '127.0.0.1:22'") 237 238 with subtest("match-rules"): 239 server_match_rule.succeed("ss -nlt | grep '127.0.0.1:22'") 240 241 with subtest("allowed-users"): 242 client.succeed( 243 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 244 ) 245 client.succeed("chmod 600 privkey.snakeoil") 246 client.succeed( 247 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil alice@server-allowed-users true", 248 timeout=30 249 ) 250 client.succeed( 251 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil bob@server-allowed-users true", 252 timeout=30 253 ) 254 client.fail( 255 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil carol@server-allowed-users true", 256 timeout=30 257 ) 258 259 with subtest("no-openssl"): 260 client.succeed( 261 "cat ${snakeOilEd25519PrivateKey} > privkey.snakeoil" 262 ) 263 client.succeed("chmod 600 privkey.snakeoil") 264 client.succeed( 265 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-no-openssl true", 266 timeout=30 267 ) 268 269 with subtest("no-pam"): 270 client.succeed( 271 "cat ${snakeOilPrivateKey} > privkey.snakeoil" 272 ) 273 client.succeed("chmod 600 privkey.snakeoil") 274 client.succeed( 275 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-no-pam true", 276 timeout=30 277 ) 278 ''; 279})