1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.fail2ban;
8
9 fail2banConf = pkgs.writeText "fail2ban.conf" cfg.daemonConfig;
10
11 jailConf = pkgs.writeText "jail.conf"
12 (concatStringsSep "\n" (attrValues (flip mapAttrs cfg.jails (name: def:
13 optionalString (def != "")
14 ''
15 [${name}]
16 ${def}
17 ''))));
18
19in
20
21{
22
23 ###### interface
24
25 options = {
26
27 services.fail2ban = {
28 enable = mkOption {
29 default = false;
30 type = types.bool;
31 description = "Whether to enable the fail2ban service.";
32 };
33
34 daemonConfig = mkOption {
35 default =
36 ''
37 [Definition]
38 loglevel = INFO
39 logtarget = SYSLOG
40 socket = /run/fail2ban/fail2ban.sock
41 pidfile = /run/fail2ban/fail2ban.pid
42 '';
43 type = types.lines;
44 description =
45 ''
46 The contents of Fail2ban's main configuration file. It's
47 generally not necessary to change it.
48 '';
49 };
50
51 jails = mkOption {
52 default = { };
53 example = literalExample ''
54 { apache-nohome-iptables = '''
55 # Block an IP address if it accesses a non-existent
56 # home directory more than 5 times in 10 minutes,
57 # since that indicates that it's scanning.
58 filter = apache-nohome
59 action = iptables-multiport[name=HTTP, port="http,https"]
60 logpath = /var/log/httpd/error_log*
61 findtime = 600
62 bantime = 600
63 maxretry = 5
64 ''';
65 }
66 '';
67 type = types.attrsOf types.lines;
68 description =
69 ''
70 The configuration of each Fail2ban “jail”. A jail
71 consists of an action (such as blocking a port using
72 <command>iptables</command>) that is triggered when a
73 filter applied to a log file triggers more than a certain
74 number of times in a certain time period. Actions are
75 defined in <filename>/etc/fail2ban/action.d</filename>,
76 while filters are defined in
77 <filename>/etc/fail2ban/filter.d</filename>.
78 '';
79 };
80
81 };
82
83 };
84
85
86 ###### implementation
87
88 config = mkIf cfg.enable {
89
90 environment.systemPackages = [ pkgs.fail2ban ];
91
92 environment.etc."fail2ban/fail2ban.conf".source = fail2banConf;
93 environment.etc."fail2ban/jail.conf".source = jailConf;
94 environment.etc."fail2ban/action.d".source = "${pkgs.fail2ban}/etc/fail2ban/action.d/*.conf";
95 environment.etc."fail2ban/filter.d".source = "${pkgs.fail2ban}/etc/fail2ban/filter.d/*.conf";
96
97 systemd.services.fail2ban =
98 { description = "Fail2ban Intrusion Prevention System";
99
100 wantedBy = [ "multi-user.target" ];
101 after = [ "network.target" ];
102
103 restartTriggers = [ fail2banConf jailConf ];
104 path = [ pkgs.fail2ban pkgs.iptables ];
105
106 preStart =
107 ''
108 mkdir -p /run/fail2ban -m 0755
109 mkdir -p /var/lib/fail2ban
110 '';
111
112 serviceConfig =
113 { ExecStart = "${pkgs.fail2ban}/bin/fail2ban-server -f";
114 ReadOnlyDirectories = "/";
115 ReadWriteDirectories = "/run /var/tmp /var/lib";
116 CapabilityBoundingSet = "CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW";
117 };
118
119 postStart =
120 ''
121 # Wait for the server to start listening.
122 for ((n = 0; n < 20; n++)); do
123 if fail2ban-client ping; then break; fi
124 sleep 0.5
125 done
126
127 # Reload its configuration.
128 fail2ban-client reload
129 '';
130 };
131
132 # Add some reasonable default jails. The special "DEFAULT" jail
133 # sets default values for all other jails.
134 services.fail2ban.jails.DEFAULT =
135 ''
136 ignoreip = 127.0.0.1/8
137 bantime = 600
138 findtime = 600
139 maxretry = 3
140 backend = systemd
141 enabled = true
142 '';
143
144 # Block SSH if there are too many failing connection attempts.
145 services.fail2ban.jails.ssh-iptables =
146 ''
147 filter = sshd
148 action = iptables[name=SSH, port=ssh, protocol=tcp]
149 maxretry = 5
150 '';
151
152 };
153
154}