Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)

ssh-audit: add test of audited configuration

On current nixpkgs, no modifications to the server settings were
necessary to pass the audit. However, some of the client algorithms were
considered insecure. The client configuration lists all algorithms which
were listed as acceptable by `ssh-audit`.

This can be used as an example of a configuration currently considered
acceptable by `ssh-audit`, and verifies that such a configuration
results in a compatible client/server configuration.

Beware that this test will continue passing when future versions of
`ssh-audit` add support for new algorithms. In other words, the example
configuration represents a subset of what the current version of
`ssh-audit` would consider acceptable.

authored by Victor Engmark and committed by Artturin c15e1f61 3e8e1782

+109
+1
nixos/tests/all-tests.nix
··· 750 750 spark = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./spark {}; 751 751 sqlite3-to-mysql = handleTest ./sqlite3-to-mysql.nix {}; 752 752 sslh = handleTest ./sslh.nix {}; 753 + ssh-audit = handleTest ./ssh-audit.nix {}; 753 754 sssd = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./sssd.nix {}; 754 755 sssd-ldap = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./sssd-ldap.nix {}; 755 756 stalwart-mail = handleTest ./stalwart-mail.nix {};
+103
nixos/tests/ssh-audit.nix
··· 1 + import ./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 + )
+5
pkgs/tools/security/ssh-audit/default.nix
··· 1 1 { lib 2 2 , fetchFromGitHub 3 + , nixosTests 3 4 , python3Packages 4 5 }: 5 6 ··· 18 19 nativeCheckInputs = with python3Packages; [ 19 20 pytestCheckHook 20 21 ]; 22 + 23 + passthru.tests = { 24 + inherit (nixosTests) ssh-audit; 25 + }; 21 26 22 27 meta = with lib; { 23 28 description = "Tool for ssh server auditing";