diff --git a/services/minecraft.nix b/services/minecraft.nix index 2b13448..ed8eac2 100644 --- a/services/minecraft.nix +++ b/services/minecraft.nix @@ -151,24 +151,4 @@ "z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name}/squaremap 710 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}" "Z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name}/squaremap/web 750 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}" ]; - - # Protect Minecraft server from connection spam / brute force attempts - # Based on https://github.com/fail2ban/fail2ban/pull/2852#issuecomment-3105039910 - # Only bans IPs that fail whitelist/ban checks - NOT legitimate player disconnects - services.fail2ban.jails.minecraft = { - enabled = true; - settings = { - backend = "auto"; - port = builtins.toString config.services.minecraft-servers.servers.${service_configs.minecraft.server_name}.serverProperties.server-port; - logpath = "${config.services.minecraft-servers.dataDir}/${service_configs.minecraft.server_name}/logs/latest.log"; - # defaults: maxretry=5, findtime=10m, bantime=10m - }; - filter.Definition = { - # Only match whitelist rejections and bans - safe patterns that won't affect legitimate players - # Format: [HH:MM:SS] [Server thread/INFO]: Disconnecting (/:): - datepattern = "^\\[%%H:%%M:%%S\\]"; - failregex = "^\\s*\\[Server thread/INFO\\]: Disconnecting .+ \\(/:\\d+\\): (?:You are not white-listed on this server|You are banned from this server)"; - ignoreregex = ""; - }; - }; } diff --git a/tests/fail2ban-minecraft.nix b/tests/fail2ban-minecraft.nix deleted file mode 100644 index 6a80412..0000000 --- a/tests/fail2ban-minecraft.nix +++ /dev/null @@ -1,170 +0,0 @@ -{ - config, - lib, - pkgs, - inputs, - ... -}: -let - testServerName = "testserver"; - - # Create pkgs with nix-minecraft overlay and unfree packages allowed - testPkgs = import inputs.nixpkgs { - system = pkgs.stdenv.targetPlatform.system; - config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "minecraft-server" ]; - overlays = [ - inputs.nix-minecraft.overlay - (import ../modules/overlays.nix) - ]; - }; - - testServiceConfigs = { - zpool_ssds = ""; - https = { - domain = "test.local"; - }; - minecraft = { - parent_dir = "/var/lib/minecraft"; - server_name = testServerName; - }; - }; - - testLib = lib.extend ( - final: prev: { - serviceMountWithZpool = - serviceName: zpool: dirs: - { ... }: - { }; - } - ); - - minecraftModule = - { config, lib, ... }: - { - imports = [ - (import ../services/minecraft.nix { - inherit config inputs; - pkgs = testPkgs; - lib = testLib; - service_configs = testServiceConfigs; - }) - ]; - # Override nixpkgs config to prevent conflicts in test environment - nixpkgs.config = lib.mkForce { - allowUnfreePredicate = pkg: builtins.elem (testPkgs.lib.getName pkg) [ "minecraft-server" ]; - }; - # Disable whitelist import to avoid missing secrets file and reduce memory - services.minecraft-servers.servers.${testServerName} = { - whitelist = lib.mkForce { }; - jvmOpts = lib.mkForce "-Xmx1G -Xms1G"; - }; - }; -in -testPkgs.testers.runNixOSTest { - name = "fail2ban-minecraft"; - - nodes = { - server = - { - config, - lib, - pkgs, - ... - }: - { - imports = [ - ../modules/security.nix - minecraftModule - ]; - - # Disable ZFS mount dependency - systemd.services."minecraft-server-${testServerName}-mounts".enable = lib.mkForce false; - systemd.services."minecraft-server-${testServerName}" = { - wants = lib.mkForce [ ]; - after = lib.mkForce [ ]; - requires = lib.mkForce [ ]; - }; - - # Override for faster testing - services.fail2ban.jails.minecraft.settings = { - maxretry = lib.mkForce 3; - findtime = lib.mkForce "5m"; - bantime = lib.mkForce "10m"; - }; - - # Create log directory and placeholder for fail2ban - systemd.tmpfiles.rules = [ - "d /var/lib/minecraft/${testServerName}/logs 0755 minecraft minecraft" - "f /var/lib/minecraft/${testServerName}/logs/latest.log 0644 minecraft minecraft" - ]; - - # Make fail2ban start after minecraft - systemd.services.fail2ban = { - wants = [ "minecraft-server-${testServerName}.service" ]; - after = [ "minecraft-server-${testServerName}.service" ]; - }; - - # Give minecraft server more resources - virtualisation.diskSize = 4 * 1024; - virtualisation.memorySize = 4 * 1024; - }; - - client = - { pkgs, ... }: - { - environment.systemPackages = [ - (pkgs.python3.withPackages (ps: [ ps.mcstatus ])) - ]; - }; - }; - - testScript = '' - import time - - start_all() - - # Wait for minecraft server to fully start - server.wait_for_unit("minecraft-server-${testServerName}.service", timeout=180) - server.wait_for_unit("fail2ban.service") - server.wait_for_open_port(25565, timeout=120) - - # Wait for server to be ready (shows "Done" in logs) - server.wait_until_succeeds( - "grep -q 'Done' /var/lib/minecraft/${testServerName}/logs/latest.log", - timeout=120 - ) - time.sleep(2) - - # Reload fail2ban now that the real log file exists - server.succeed("fail2ban-client reload minecraft") - time.sleep(2) - - with subtest("Verify minecraft jail is active"): - status = server.succeed("fail2ban-client status") - print(f"fail2ban status:\n{status}") - assert "minecraft" in status, f"minecraft jail not found in: {status}" - - with subtest("Verify jail configuration"): - # Check jail status shows it's monitoring the log file - status = server.succeed("fail2ban-client status minecraft") - print(f"Jail status:\n{status}") - assert "minecraft" in status, "minecraft jail not properly configured" - - with subtest("Check server logs"): - logs = server.succeed("tail -20 /var/lib/minecraft/${testServerName}/logs/latest.log") - print(f"Server logs:\n{logs}") - - with subtest("Test regex with fail2ban-regex"): - # Test the filter regex against the log file - result = server.execute("fail2ban-regex /var/lib/minecraft/${testServerName}/logs/latest.log /etc/fail2ban/filter.d/minecraft.local 2>&1") - print(f"Regex test result:\n{result}") - - with subtest("Verify jail is functional"): - # The jail should be running and monitoring - mcstatus won't trigger bans - # since it only does status pings, not login attempts that would fail whitelist - status = server.succeed("fail2ban-client status minecraft") - print(f"Final jail status:\n{status}") - # Verify the jail is running (has filter file loaded) - assert "Filter" in status or "File list" in status or "Currently" in status, "Jail not properly running" - ''; -} diff --git a/tests/tests.nix b/tests/tests.nix index 3b71c8f..fcc29e1 100644 --- a/tests/tests.nix +++ b/tests/tests.nix @@ -20,5 +20,4 @@ in fail2banVaultwardenTest = handleTest ./fail2ban-vaultwarden.nix; fail2banImmichTest = handleTest ./fail2ban-immich.nix; fail2banJellyfinTest = handleTest ./fail2ban-jellyfin.nix; - fail2banMinecraftTest = handleTest ./fail2ban-minecraft.nix; }