Files
server-config/tests/fail2ban-ssh.nix
2026-01-20 19:48:20 -05:00

105 lines
2.6 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
testServiceConfigs = {
zpool_ssds = "";
zpool_hdds = "";
};
securityModule = import ../modules/security.nix;
sshModule =
{
config,
lib,
pkgs,
...
}:
{
imports = [
(import ../services/ssh.nix {
inherit config lib pkgs;
username = "testuser";
})
];
};
in
pkgs.testers.runNixOSTest {
name = "fail2ban-ssh";
nodes = {
server =
{
config,
lib,
pkgs,
...
}:
{
imports = [
securityModule
sshModule
];
# Override for testing - enable password auth
services.openssh.settings.PasswordAuthentication = lib.mkForce true;
users.users.testuser = {
isNormalUser = true;
password = "correctpassword";
};
networking.firewall.allowedTCPPorts = [ 22 ];
};
client = {
environment.systemPackages = with pkgs; [
sshpass
openssh
];
};
};
testScript = ''
import time
start_all()
server.wait_for_unit("sshd.service")
server.wait_for_unit("fail2ban.service")
server.wait_for_open_port(22)
time.sleep(2)
with subtest("Verify sshd jail is active"):
status = server.succeed("fail2ban-client status")
assert "sshd" in status, f"sshd jail not found in: {status}"
with subtest("Generate failed SSH login attempts"):
# Use -4 to force IPv4, timeout and NumberOfPasswordPrompts=1 to ensure quick failure
# maxRetry is 3 in our config, so 4 attempts should trigger a ban
for i in range(4):
client.execute(
"timeout 5 sshpass -p 'wrongpassword' ssh -4 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=3 -o NumberOfPasswordPrompts=1 testuser@server echo test 2>/dev/null || true"
)
time.sleep(1)
with subtest("Verify IP is banned"):
# Wait for fail2ban to process the logs and apply the ban
time.sleep(5)
status = server.succeed("fail2ban-client status sshd")
print(f"sshd jail status: {status}")
# Check that at least 1 IP is banned
import re
match = re.search(r"Currently banned:\s*(\d+)", status)
assert match and int(match.group(1)) >= 1, f"Expected at least 1 banned IP, got: {status}"
with subtest("Verify banned client cannot connect"):
# Use -4 to test with same IP that was banned
exit_code = client.execute("timeout 3 nc -4 -z -w 2 server 22")[0]
assert exit_code != 0, "Connection should be blocked for banned IP"
'';
}