potentially fix fail2ban
This commit is contained in:
@@ -92,13 +92,14 @@ in
|
|||||||
|
|
||||||
# Ignore local network IPs - NAT hairpinning causes all LAN traffic to
|
# Ignore local network IPs - NAT hairpinning causes all LAN traffic to
|
||||||
# appear from the router IP (192.168.1.1). Banning it blocks all internal access.
|
# appear from the router IP (192.168.1.1). Banning it blocks all internal access.
|
||||||
# Browser subrequests for static assets (favicon.ico, etc.) without Authorization
|
|
||||||
# headers cause 401s that quickly trigger the ban threshold.
|
|
||||||
ignoreip = "127.0.0.1/8 ::1 192.168.1.0/24";
|
ignoreip = "127.0.0.1/8 ::1 192.168.1.0/24";
|
||||||
};
|
};
|
||||||
filter.Definition = {
|
filter.Definition = {
|
||||||
# Match Caddy JSON logs with 401 Unauthorized status (failed basic auth)
|
# Only match 401s where an Authorization header was actually sent.
|
||||||
failregex = ''^.*"remote_ip":"<HOST>".*"status":401.*$'';
|
# Without this, the normal HTTP Basic Auth challenge-response flow
|
||||||
|
# (browser probes without credentials, gets 401, then resends with
|
||||||
|
# credentials) counts every page visit as a "failure."
|
||||||
|
failregex = ''^.*"remote_ip":"<HOST>".*"Authorization":\["REDACTED"\].*"status":401.*$'';
|
||||||
ignoreregex = "";
|
ignoreregex = "";
|
||||||
datepattern = ''"ts":{Epoch}\.'';
|
datepattern = ''"ts":{Epoch}\.'';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ pkgs.testers.runNixOSTest {
|
|||||||
maxretry = 3; # Lower for testing
|
maxretry = 3; # Lower for testing
|
||||||
};
|
};
|
||||||
filter.Definition = {
|
filter.Definition = {
|
||||||
failregex = ''^.*"remote_ip":"<HOST>".*"status":401.*$'';
|
# Only match 401s where an Authorization header was actually sent
|
||||||
|
failregex = ''^.*"remote_ip":"<HOST>".*"Authorization":\["REDACTED"\].*"status":401.*$'';
|
||||||
ignoreregex = "";
|
ignoreregex = "";
|
||||||
datepattern = ''"ts":{Epoch}\.'';
|
datepattern = ''"ts":{Epoch}\.'';
|
||||||
};
|
};
|
||||||
@@ -86,13 +87,28 @@ pkgs.testers.runNixOSTest {
|
|||||||
print(f"Curl result: {result}")
|
print(f"Curl result: {result}")
|
||||||
assert "Authenticated" in result, f"Auth should succeed: {result}"
|
assert "Authenticated" in result, f"Auth should succeed: {result}"
|
||||||
|
|
||||||
with subtest("Generate failed basic auth attempts"):
|
with subtest("Unauthenticated requests (browser probes) should not trigger ban"):
|
||||||
|
# Simulate browser probe requests - no Authorization header sent
|
||||||
|
# This is the normal HTTP Basic Auth challenge-response flow:
|
||||||
|
# browser sends request without credentials, gets 401, then resends with credentials
|
||||||
|
for i in range(5):
|
||||||
|
client.execute("curl -4 -s http://server/ || true")
|
||||||
|
time.sleep(0.5)
|
||||||
|
time.sleep(3)
|
||||||
|
status = server.succeed("fail2ban-client status caddy-auth")
|
||||||
|
print(f"caddy-auth jail status after unauthenticated requests: {status}")
|
||||||
|
match = re.search(r"Currently banned:\s*(\d+)", status)
|
||||||
|
banned = int(match.group(1)) if match else 0
|
||||||
|
assert banned == 0, f"Unauthenticated 401s should NOT trigger ban, but {banned} IPs were banned: {status}"
|
||||||
|
|
||||||
|
with subtest("Generate failed basic auth attempts (wrong password)"):
|
||||||
# Use -4 to force IPv4 for consistent IP tracking
|
# Use -4 to force IPv4 for consistent IP tracking
|
||||||
|
# These send an Authorization header with wrong credentials
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
client.execute("curl -4 -s -u testuser:wrongpass http://server/ || true")
|
client.execute("curl -4 -s -u testuser:wrongpass http://server/ || true")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
with subtest("Verify IP is banned"):
|
with subtest("Verify IP is banned after wrong password attempts"):
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
status = server.succeed("fail2ban-client status caddy-auth")
|
status = server.succeed("fail2ban-client status caddy-auth")
|
||||||
print(f"caddy-auth jail status: {status}")
|
print(f"caddy-auth jail status: {status}")
|
||||||
|
|||||||
Reference in New Issue
Block a user