+37
-46
services/fail2ban/default.nix
+37
-46
services/fail2ban/default.nix
···
1
-
{ config, pkgs, ... }:
1
+
{ pkgs, ... }:
2
2
3
3
{
4
4
age.secrets.abuseipdb = {
···
49
49
maxretry = 5;
50
50
findtime = "3600";
51
51
bantime = "86400";
52
-
action = "iptables-multiport[name=SSH, port='ssh']\nabuseipdb[abuseipdb_apikey='$(cat /run/agenix/abuseipdb)', abuseipdb_category='18,22']";
52
+
action = "iptables-multiport[name=SSH, port='ssh']\nabuseipdb-agenix[abuseipdb_category='18,22']";
53
53
};
54
54
55
55
# Caddy HTTP/HTTPS protection - monitor for repeated 4xx/5xx errors
···
62
62
maxretry = 10;
63
63
findtime = "600";
64
64
bantime = "3600";
65
-
action = "iptables-multiport[name=Caddy, port='http,https']\nabuseipdb[abuseipdb_apikey='$(cat /run/agenix/abuseipdb)', abuseipdb_category='21']";
65
+
action = "iptables-multiport[name=Caddy, port='http,https']\nabuseipdb-agenix[abuseipdb_category='21']";
66
66
};
67
67
68
68
# Rate-based protection - ban on excessive requests
···
75
75
maxretry = 50;
76
76
findtime = "60";
77
77
bantime = "1800";
78
-
action = "iptables-multiport[name=Caddy-RateLimit, port='http,https']\nabuseipdb[abuseipdb_apikey='$(cat /run/agenix/abuseipdb)', abuseipdb_category='21']";
78
+
action = "iptables-multiport[name=Caddy-RateLimit, port='http,https']\nabuseipdb-agenix[abuseipdb_category='21']";
79
79
};
80
80
};
81
81
};
82
82
83
-
# Custom filters and actions for Fail2Ban
84
-
environment.etc =
85
-
let
86
-
abuseipdbAction = ''
87
-
[Definition]
88
-
actionstart =
89
-
actionstop =
90
-
actioncheck =
83
+
# Custom filters for Fail2Ban
84
+
environment.etc = {
85
+
# Caddy HTTP error monitoring filter
86
+
"fail2ban/filter.d/caddy-http.conf".text = ''
87
+
[Definition]
88
+
failregex = ^<HOST> -.*" (?:400|401|403|404|405|429|500|502|503|504) .*$
89
+
ignoreregex =
90
+
'';
91
91
92
-
# Report IP to AbuseIPDB using official fail2ban pattern
93
-
# The abuseipdb_apikey parameter is passed from the jail action call
94
-
actionban = lgm=$(printf '%%.1000s\n...' "<matches>"); curl -sSf "https://api.abuseipdb.com/api/v2/report" \
95
-
-H "Accept: application/json" \
96
-
-H "Key: <abuseipdb_apikey>" \
97
-
--data-urlencode "comment=$lgm" \
98
-
--data-urlencode "ip=<ip>" \
99
-
--data "categories=<abuseipdb_category>"
92
+
# Caddy rate limiting filter - detects repeated requests within short timeframe
93
+
"fail2ban/filter.d/caddy-ratelimit.conf".text = ''
94
+
[Definition]
95
+
failregex = ^<HOST> -.*" \d{3} .*$
96
+
ignoreregex =
97
+
'';
100
98
101
-
# No action to unban - AbuseIPDB reports are permanent
102
-
actionunban =
99
+
# Custom abuseipdb action that reads API key from file
100
+
"fail2ban/action.d/abuseipdb-agenix.conf".text = ''
101
+
[Definition]
102
+
# Report IP to AbuseIPDB, reading API key from Agenix secret file
103
+
# The entire command is wrapped in /bin/sh -c to ensure shell expansion of $(cat ...)
104
+
actionban = /bin/sh -c 'lgm=$(printf "%%.1000s\n..." "<matches>"); curl -sSf "https://api.abuseipdb.com/api/v2/report" \
105
+
-H "Accept: application/json" \
106
+
-H "Key: $(cat /run/agenix/abuseipdb)" \
107
+
--data-urlencode "comment=$lgm" \
108
+
--data-urlencode "ip=<ip>" \
109
+
--data "categories=<abuseipdb_category>"'
103
110
104
-
[Init]
105
-
# Default category for abuse report
106
-
abuseipdb_category = 18
107
-
# API key must be provided in jail action call
108
-
abuseipdb_apikey =
109
-
'';
110
-
in
111
-
{
112
-
# Caddy HTTP error monitoring filter
113
-
"fail2ban/filter.d/caddy-http.conf".text = ''
114
-
[Definition]
115
-
failregex = ^<HOST> -.*" (?:400|401|403|404|405|429|500|502|503|504) .*$
116
-
ignoreregex =
117
-
'';
111
+
actionstart =
112
+
actionstop =
113
+
actioncheck =
114
+
actionunban =
118
115
119
-
# Caddy rate limiting filter - detects repeated requests within short timeframe
120
-
"fail2ban/filter.d/caddy-ratelimit.conf".text = ''
121
-
[Definition]
122
-
failregex = ^<HOST> -.*" \d{3} .*$
123
-
ignoreregex =
124
-
'';
125
-
126
-
# AbuseIPDB action - must be copied into action.d directory
127
-
"fail2ban/action.d/abuseipdb.conf".text = abuseipdbAction;
128
-
};
116
+
[Init]
117
+
abuseipdb_category = 18
118
+
'';
119
+
};
129
120
130
121
# Ensure the log directory exists
131
122
systemd.tmpfiles.rules = [