python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / security / fail2ban.nix
blobe208eed008ae03b8c0e07275ed07a4eacafbc8cf
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   cfg = config.services.fail2ban;
9   fail2banConf = pkgs.writeText "fail2ban.local" cfg.daemonConfig;
11   jailConf = pkgs.writeText "jail.local" ''
12     [INCLUDES]
14     before = paths-nixos.conf
16     ${concatStringsSep "\n" (attrValues (flip mapAttrs cfg.jails (name: def:
17       optionalString (def != "")
18         ''
19           [${name}]
20           ${def}
21         '')))}
22   '';
24   pathsConf = pkgs.writeText "paths-nixos.conf" ''
25     # NixOS
27     [INCLUDES]
29     before = paths-common.conf
31     after  = paths-overrides.local
33     [DEFAULT]
34   '';
40   ###### interface
42   options = {
44     services.fail2ban = {
45       enable = mkOption {
46         default = false;
47         type = types.bool;
48         description = lib.mdDoc ''
49           Whether to enable the fail2ban service.
51           See the documentation of {option}`services.fail2ban.jails`
52           for what jails are enabled by default.
53         '';
54       };
56       package = mkOption {
57         default = pkgs.fail2ban;
58         defaultText = literalExpression "pkgs.fail2ban";
59         type = types.package;
60         example = literalExpression "pkgs.fail2ban_0_11";
61         description = lib.mdDoc "The fail2ban package to use for running the fail2ban service.";
62       };
64       packageFirewall = mkOption {
65         default = pkgs.iptables;
66         defaultText = literalExpression "pkgs.iptables";
67         type = types.package;
68         example = literalExpression "pkgs.nftables";
69         description = lib.mdDoc "The firewall package used by fail2ban service.";
70       };
72       extraPackages = mkOption {
73         default = [];
74         type = types.listOf types.package;
75         example = lib.literalExpression "[ pkgs.ipset ]";
76         description = lib.mdDoc ''
77           Extra packages to be made available to the fail2ban service. The example contains
78           the packages needed by the `iptables-ipset-proto6` action.
79         '';
80       };
82       maxretry = mkOption {
83         default = 3;
84         type = types.ints.unsigned;
85         description = lib.mdDoc "Number of failures before a host gets banned.";
86       };
88       banaction = mkOption {
89         default = "iptables-multiport";
90         type = types.str;
91         example = "nftables-multiport";
92         description = lib.mdDoc ''
93           Default banning action (e.g. iptables, iptables-new, iptables-multiport,
94           iptables-ipset-proto6-allports, shorewall, etc) It is used to
95           define action_* variables. Can be overridden globally or per
96           section within jail.local file
97         '';
98       };
100       banaction-allports = mkOption {
101         default = "iptables-allport";
102         type = types.str;
103         example = "nftables-allport";
104         description = lib.mdDoc ''
105           Default banning action (e.g. iptables, iptables-new, iptables-multiport,
106           shorewall, etc) It is used to define action_* variables. Can be overridden
107           globally or per section within jail.local file
108         '';
109       };
111       bantime-increment.enable = mkOption {
112         default = false;
113         type = types.bool;
114         description = lib.mdDoc ''
115           Allows to use database for searching of previously banned ip's to increase
116           a default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
117         '';
118       };
120       bantime-increment.rndtime = mkOption {
121         default = "4m";
122         type = types.str;
123         example = "8m";
124         description = lib.mdDoc ''
125           "bantime-increment.rndtime" is the max number of seconds using for mixing with random time
126           to prevent "clever" botnets calculate exact time IP can be unbanned again
127         '';
128       };
130       bantime-increment.maxtime = mkOption {
131         default = "10h";
132         type = types.str;
133         example = "48h";
134         description = lib.mdDoc ''
135           "bantime-increment.maxtime" is the max number of seconds using the ban time can reach (don't grows further)
136         '';
137       };
139       bantime-increment.factor = mkOption {
140         default = "1";
141         type = types.str;
142         example = "4";
143         description = lib.mdDoc ''
144           "bantime-increment.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
145           default value of factor is 1 and with default value of formula, the ban time grows by 1, 2, 4, 8, 16 ...
146         '';
147       };
149       bantime-increment.formula = mkOption {
150         default = "ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor";
151         type = types.str;
152         example = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)";
153         description = lib.mdDoc ''
154           "bantime-increment.formula" used by default to calculate next value of ban time, default value bellow,
155           the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
156         '';
157       };
159       bantime-increment.multipliers = mkOption {
160         default = "1 2 4 8 16 32 64";
161         type = types.str;
162         example = "2 4 16 128";
163         description = lib.mdDoc ''
164           "bantime-increment.multipliers" used to calculate next value of ban time instead of formula, coresponding
165           previously ban count and given "bantime.factor" (for multipliers default is 1);
166           following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count,
167           always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
168         '';
169       };
171       bantime-increment.overalljails = mkOption {
172         default = false;
173         type = types.bool;
174         example = true;
175         description = lib.mdDoc ''
176           "bantime-increment.overalljails"  (if true) specifies the search of IP in the database will be executed
177           cross over all jails, if false (dafault), only current jail of the ban IP will be searched
178         '';
179       };
181       ignoreIP = mkOption {
182         default = [ ];
183         type = types.listOf types.str;
184         example = [ "192.168.0.0/16" "2001:DB8::42" ];
185         description = lib.mdDoc ''
186           "ignoreIP" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban will not ban a host which
187           matches an address in this list. Several addresses can be defined using space (and/or comma) separator.
188         '';
189       };
191       daemonConfig = mkOption {
192         default = ''
193           [Definition]
194           logtarget = SYSLOG
195           socket    = /run/fail2ban/fail2ban.sock
196           pidfile   = /run/fail2ban/fail2ban.pid
197           dbfile    = /var/lib/fail2ban/fail2ban.sqlite3
198         '';
199         type = types.lines;
200         description = lib.mdDoc ''
201           The contents of Fail2ban's main configuration file.  It's
202           generally not necessary to change it.
203        '';
204       };
206       jails = mkOption {
207         default = { };
208         example = literalExpression ''
209           { apache-nohome-iptables = '''
210               # Block an IP address if it accesses a non-existent
211               # home directory more than 5 times in 10 minutes,
212               # since that indicates that it's scanning.
213               filter   = apache-nohome
214               action   = iptables-multiport[name=HTTP, port="http,https"]
215               logpath  = /var/log/httpd/error_log*
216               backend = auto
217               findtime = 600
218               bantime  = 600
219               maxretry = 5
220             ''';
221            dovecot = '''
222              # block IPs which failed to log-in
223              # aggressive mode add blocking for aborted connections
224              enabled = true
225              filter = dovecot[mode=aggressive]
226              maxretry = 3
227            ''';
228           }
229         '';
230         type = types.attrsOf types.lines;
231         description = lib.mdDoc ''
232           The configuration of each Fail2ban “jail”.  A jail
233           consists of an action (such as blocking a port using
234           {command}`iptables`) that is triggered when a
235           filter applied to a log file triggers more than a certain
236           number of times in a certain time period.  Actions are
237           defined in {file}`/etc/fail2ban/action.d`,
238           while filters are defined in
239           {file}`/etc/fail2ban/filter.d`.
241           NixOS comes with a default `sshd` jail;
242           for it to work well,
243           {option}`services.openssh.logLevel` should be set to
244           `"VERBOSE"` or higher so that fail2ban
245           can observe failed login attempts.
246           This module sets it to `"VERBOSE"` if
247           not set otherwise, so enabling fail2ban can make SSH logs
248           more verbose.
249         '';
250       };
252     };
254   };
256   ###### implementation
258   config = mkIf cfg.enable {
260     warnings = mkIf (config.networking.firewall.enable == false && config.networking.nftables.enable == false) [
261       "fail2ban can not be used without a firewall"
262     ];
264     environment.systemPackages = [ cfg.package ];
266     environment.etc = {
267       "fail2ban/fail2ban.local".source = fail2banConf;
268       "fail2ban/jail.local".source = jailConf;
269       "fail2ban/fail2ban.conf".source = "${cfg.package}/etc/fail2ban/fail2ban.conf";
270       "fail2ban/jail.conf".source = "${cfg.package}/etc/fail2ban/jail.conf";
271       "fail2ban/paths-common.conf".source = "${cfg.package}/etc/fail2ban/paths-common.conf";
272       "fail2ban/paths-nixos.conf".source = pathsConf;
273       "fail2ban/action.d".source = "${cfg.package}/etc/fail2ban/action.d/*.conf";
274       "fail2ban/filter.d".source = "${cfg.package}/etc/fail2ban/filter.d/*.conf";
275     };
277     systemd.services.fail2ban = {
278       description = "Fail2ban Intrusion Prevention System";
280       wantedBy = [ "multi-user.target" ];
281       after = [ "network.target" ];
282       partOf = optional config.networking.firewall.enable "firewall.service";
284       restartTriggers = [ fail2banConf jailConf pathsConf ];
286       path = [ cfg.package cfg.packageFirewall pkgs.iproute2 ] ++ cfg.extraPackages;
288       unitConfig.Documentation = "man:fail2ban(1)";
290       serviceConfig = {
291         ExecStart = "${cfg.package}/bin/fail2ban-server -xf start";
292         ExecStop = "${cfg.package}/bin/fail2ban-server stop";
293         ExecReload = "${cfg.package}/bin/fail2ban-server reload";
294         Type = "simple";
295         Restart = "on-failure";
296         PIDFile = "/run/fail2ban/fail2ban.pid";
297         # Capabilities
298         CapabilityBoundingSet = [ "CAP_AUDIT_READ" "CAP_DAC_READ_SEARCH" "CAP_NET_ADMIN" "CAP_NET_RAW" ];
299         # Security
300         NoNewPrivileges = true;
301         # Directory
302         RuntimeDirectory = "fail2ban";
303         RuntimeDirectoryMode = "0750";
304         StateDirectory = "fail2ban";
305         StateDirectoryMode = "0750";
306         LogsDirectory = "fail2ban";
307         LogsDirectoryMode = "0750";
308         # Sandboxing
309         ProtectSystem = "strict";
310         ProtectHome = true;
311         PrivateTmp = true;
312         PrivateDevices = true;
313         ProtectHostname = true;
314         ProtectKernelTunables = true;
315         ProtectKernelModules = true;
316         ProtectControlGroups = true;
317       };
318     };
320     # Add some reasonable default jails.  The special "DEFAULT" jail
321     # sets default values for all other jails.
322     services.fail2ban.jails.DEFAULT = ''
323       ${optionalString cfg.bantime-increment.enable ''
324         # Bantime incremental
325         bantime.increment    = ${boolToString cfg.bantime-increment.enable}
326         bantime.maxtime      = ${cfg.bantime-increment.maxtime}
327         bantime.factor       = ${cfg.bantime-increment.factor}
328         bantime.formula      = ${cfg.bantime-increment.formula}
329         bantime.multipliers  = ${cfg.bantime-increment.multipliers}
330         bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails}
331       ''}
332       # Miscellaneous options
333       ignoreip    = 127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP}
334       maxretry    = ${toString cfg.maxretry}
335       backend     = systemd
336       # Actions
337       banaction   = ${cfg.banaction}
338       banaction_allports = ${cfg.banaction-allports}
339     '';
340     # Block SSH if there are too many failing connection attempts.
341     # Benefits from verbose sshd logging to observe failed login attempts,
342     # so we set that here unless the user overrode it.
343     services.openssh.logLevel = lib.mkDefault "VERBOSE";
344     services.fail2ban.jails.sshd = mkDefault ''
345       enabled = true
346       port    = ${concatMapStringsSep "," (p: toString p) config.services.openssh.ports}
347     '';
348   };