1import ./make-test-python.nix (
2 {pkgs, ...}: let
3 sshKeys = import (pkgs.path + "/nixos/tests/ssh-keys.nix") pkgs;
4 sshUsername = "any-user";
5 serverName = "server";
6 clientName = "client";
7 sshAuditPort = 2222;
8 in {
9 name = "ssh";
10
11 nodes = {
12 "${serverName}" = {
13 networking.firewall.allowedTCPPorts = [
14 sshAuditPort
15 ];
16 services.openssh.enable = true;
17 users.users."${sshUsername}" = {
18 isNormalUser = true;
19 openssh.authorizedKeys.keys = [
20 sshKeys.snakeOilPublicKey
21 ];
22 };
23 };
24 "${clientName}" = {
25 programs.ssh = {
26 ciphers = [
27 "aes128-ctr"
28 "aes128-gcm@openssh.com"
29 "aes192-ctr"
30 "aes256-ctr"
31 "aes256-gcm@openssh.com"
32 "chacha20-poly1305@openssh.com"
33 ];
34 extraConfig = ''
35 IdentitiesOnly yes
36 '';
37 hostKeyAlgorithms = [
38 "rsa-sha2-256"
39 "rsa-sha2-256-cert-v01@openssh.com"
40 "rsa-sha2-512"
41 "rsa-sha2-512-cert-v01@openssh.com"
42 "sk-ssh-ed25519-cert-v01@openssh.com"
43 "sk-ssh-ed25519@openssh.com"
44 "ssh-ed25519"
45 "ssh-ed25519-cert-v01@openssh.com"
46 ];
47 kexAlgorithms = [
48 "curve25519-sha256"
49 "curve25519-sha256@libssh.org"
50 "diffie-hellman-group-exchange-sha256"
51 "diffie-hellman-group16-sha512"
52 "diffie-hellman-group18-sha512"
53 "sntrup761x25519-sha512@openssh.com"
54 ];
55 macs = [
56 "hmac-sha2-256-etm@openssh.com"
57 "hmac-sha2-512-etm@openssh.com"
58 "umac-128-etm@openssh.com"
59 ];
60 };
61 };
62 };
63
64 testScript = ''
65 start_all()
66
67 ${serverName}.wait_for_open_port(22)
68
69 # Should pass SSH server audit
70 ${serverName}.succeed("${pkgs.ssh-audit}/bin/ssh-audit 127.0.0.1")
71
72 # Wait for client to be able to connect to the server
73 ${clientName}.wait_for_unit("network-online.target")
74
75 # Set up trusted private key
76 ${clientName}.succeed("cat ${sshKeys.snakeOilPrivateKey} > privkey.snakeoil")
77 ${clientName}.succeed("chmod 600 privkey.snakeoil")
78
79 # Fail fast and disable interactivity
80 ssh_options = "-o BatchMode=yes -o ConnectTimeout=1 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
81
82 # Should deny root user
83 ${clientName}.fail(f"ssh {ssh_options} root@${serverName} true")
84
85 # Should deny non-root user password login
86 ${clientName}.fail(f"ssh {ssh_options} -o PasswordAuthentication=yes ${sshUsername}@${serverName} true")
87
88 # Should allow non-root user certificate login
89 ${clientName}.succeed(f"ssh {ssh_options} -i privkey.snakeoil ${sshUsername}@${serverName} true")
90
91 # Should pass SSH client audit
92 service_name = "ssh-audit.service"
93 ${serverName}.succeed(f"systemd-run --unit={service_name} ${pkgs.ssh-audit}/bin/ssh-audit --client-audit --port=${toString sshAuditPort}")
94 ${clientName}.sleep(5) # We can't use wait_for_open_port because ssh-audit exits as soon as anything talks to it
95 ${clientName}.execute(
96 f"ssh {ssh_options} -i privkey.snakeoil -p ${toString sshAuditPort} ${sshUsername}@${serverName} true",
97 check_return=False,
98 timeout=10
99 )
100 ${serverName}.succeed(f"exit $(systemctl show --property=ExecMainStatus --value {service_name})")
101 '';
102 }
103)