Commit 5771a375f69d

Vincent Demeester <vincent@sbr.pm>
2026-02-23 15:28:06
feat(kerkouane): add fail2ban and SYN flood protection
Added fail2ban with three Caddy jails (auth brute-force, 404 scanning, request flooding) using custom JSON log filters and progressive ban escalation up to 1 week. Added iptables connlimit rule to mitigate SYN flood attacks from botnets.
1 parent eeca3b3
Changed files (1)
systems
kerkouane
systems/kerkouane/extra.nix
@@ -104,6 +104,90 @@ in
     ../common/services/openssh.nix
   ];
 
+  # ── Fail2ban ────────────────────────────────────────────────────────
+  services.fail2ban = {
+    enable = true;
+
+    # Ban for 1 hour, increase on repeat offenders via recidive jail
+    bantime = "1h";
+    bantime-increment = {
+      enable = true;
+      maxtime = "168h"; # Max 1 week ban
+      factor = "4"; # Aggressive escalation
+    };
+
+    maxretry = 5;
+
+    # Ignore VPN and loopback
+    ignoreIP = [
+      "127.0.0.0/8"
+      "::1"
+      "10.100.0.0/24" # WireGuard VPN
+    ];
+
+    jails = {
+      # Caddy auth failures (401/403 responses)
+      caddy-auth = ''
+        enabled = true
+        backend = auto
+        filter = caddy-auth
+        logpath = /var/log/caddy/access*.log
+        maxretry = 10
+        findtime = 600
+        bantime = 3600
+      '';
+
+      # Caddy aggressive scanning (404 floods)
+      caddy-scan = ''
+        enabled = true
+        backend = auto
+        filter = caddy-scan
+        logpath = /var/log/caddy/access*.log
+        maxretry = 30
+        findtime = 60
+        bantime = 3600
+      '';
+
+      # Caddy rate abuse (too many requests)
+      caddy-flood = ''
+        enabled = true
+        backend = auto
+        filter = caddy-flood
+        logpath = /var/log/caddy/access*.log
+        maxretry = 200
+        findtime = 60
+        bantime = 7200
+      '';
+    };
+  };
+
+  # Caddy fail2ban filters for JSON access logs
+  environment.etc = {
+    # Ban IPs that get too many 401/403 responses (brute force / unauthorized access)
+    "fail2ban/filter.d/caddy-auth.conf".text = ''
+      [Definition]
+      failregex = ^.*"remote_ip":"<HOST>".*"status":(401|403),.*$
+      ignoreregex =
+      datepattern = "ts":{EPOCH}
+    '';
+
+    # Ban IPs that trigger excessive 404s (scanning for vulnerabilities)
+    "fail2ban/filter.d/caddy-scan.conf".text = ''
+      [Definition]
+      failregex = ^.*"remote_ip":"<HOST>".*"status":404,.*$
+      ignoreregex =
+      datepattern = "ts":{EPOCH}
+    '';
+
+    # Ban IPs with excessive request volume (flood / DDoS)
+    "fail2ban/filter.d/caddy-flood.conf".text = ''
+      [Definition]
+      failregex = ^.*"remote_ip":"<HOST>".*"status":\d+,.*$
+      ignoreregex = ^.*"remote_ip":"10\.100\.0\..*$
+      datepattern = "ts":{EPOCH}
+    '';
+  };
+
   # Age secrets
   age.secrets."ntfy-token" = {
     file = ../../secrets/sakhalin/ntfy-token.age;
@@ -357,6 +441,9 @@ in
     extraCommands = ''
       # Allow node exporter (9000) only from VPN network
       iptables -A nixos-fw -p tcp -s 10.100.0.0/16 --dport 9000 -j nixos-fw-accept
+
+      # SYN flood protection: limit new connections per /24 subnet
+      iptables -A nixos-fw -p tcp --syn -m connlimit --connlimit-above 30 --connlimit-mask 24 -j DROP
     '';
   };
   # Allow Caddy to access public git repositories only (override ProtectHome)