{ pkgs, ... }: { # References: # https://blog.lrvt.de/configuring-fail2ban-with-traefik/ # https://nixos.wiki/wiki/Fail2ban#Extending_Fail2ban services.logrotate = { enable = true; checkConfig = true; settings = { "/var/log/traefik/access.log" = { frequency = "daily"; rotate = 30; }; }; }; services.fail2ban.jails = { traefik-general-forceful-browsing = { settings = { enabled = true; filter = "traefik-general-forceful-browsing"; action = "action-ban-docker-forceful-browsing"; logpath = "/var/log/traefik/access.log"; backend = "auto"; findtime = 600; bantime = 600; maxretry = 5; }; }; }; environment.etc= { "fail2ban/filter.d/traefik-general-forceful-browsing.conf".text = pkgs.lib.mkDefault (pkgs.lib.mkAfter '' [INCLUDES] [Definition] # fail regex based on traefik JSON access logs with enabled user agent logging failregex = ^{"ClientAddr":".*","ClientHost":"","ClientPort":".*","ClientUsername":".*","DownstreamContentSize":.*,"DownstreamStatus":.*,"Duration":.*,"OriginContentSize":.*,"OriginDuration":.*,"OriginStatus":(405|404|403|402|401),"Overhead":.*,"RequestAddr":".*","RequestContentSize":.*,"RequestCount":.*,"RequestHost":".*","RequestMethod":".*","RequestPath":".*","RequestPort":".*","RequestProtocol":".*","RequestScheme":".*","RetryAttempts":.*,.*"StartLocal":".*","StartUTC":".*","TLSCipher":".*","TLSVersion":".*","entryPointName":".*","level":".*","msg":".*",("request_User-Agent":".*",){0,1}?"time":".*"}$ # custom date pattern for traefik JSON access logs # based on https://github.com/fail2ban/fail2ban/issues/2558#issuecomment-546738270 datepattern = "StartLocal"\s*:\s*"%%Y-%%m-%%d[T]%%H:%%M:%%S\.%%f\d*(%%z)?", # ignore common errors like missing media files or JS/CSS/TXT/ICO stuff ignoreregex = ^{"ClientAddr":".*","ClientHost":"","ClientPort":".*","ClientUsername":".*","DownstreamContentSize":.*,"DownstreamStatus":.*,"Duration":.*,"OriginContentSize":.*,"OriginDuration":.*,"OriginStatus":(405|404|403|402|401),"Overhead":.*,"RequestAddr":".*","RequestContentSize":.*,"RequestCount":.*,"RequestHost":".*","RequestMethod":".*","RequestPath":".*(\.png|\.txt|\.jpg|\.ico|\.js|\.css|\.ttf|\.woff|\.woff2)(/)*?","RequestPort":".*","RequestProtocol":".*","RequestScheme":".*","RetryAttempts":.*,.*"StartLocal":".*","StartUTC":".*","TLSCipher":".*","TLSVersion":".*","entryPointName":".*","level":".*","msg":".*",("request_User-Agent":".*",){0,1}?"time":".*"}$ ''); "fail2ban/action.d/action-ban-docker-forceful-browsing.conf".text = pkgs.lib.mkDefault (pkgs.lib.mkAfter '' [Definition] actionban = ${pkgs.iptables}/bin/iptables -I DOCKER-USER -m string --algo bm --string 'X-Forwarded-For: ' -j DROP ${pkgs.iptables}/bin/iptables -A INPUT -s -j DROP actionunban = ${pkgs.iptables}/bin/iptables -D DOCKER-USER -m string --algo bm --string 'X-Forwarded-For: ' -j DROP ${pkgs.iptables}/bin/iptables -D INPUT -s -j DROP ''); }; }