summary refs log tree commit diff
path: root/nixos/modules/services/security/fail2ban.nix
blob: ae1fd22d23ee7e86308abf2021da2b3519dcfb9c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
{ config, pkgs, ... }:

with pkgs.lib;

let

  cfg = config.services.fail2ban;

  fail2banConf = pkgs.writeText "fail2ban.conf" cfg.daemonConfig;

  jailConf = pkgs.writeText "jail.conf"
    (concatStringsSep "\n" (attrValues (flip mapAttrs cfg.jails (name: def:
      optionalString (def != "")
        ''
          [${name}]
          ${def}
        ''))));

in

{

  ###### interface

  options = {

    services.fail2ban = {

      daemonConfig = mkOption {
        default =
          ''
            [Definition]
            loglevel  = 3
            logtarget = SYSLOG
            socket    = /run/fail2ban/fail2ban.sock
            pidfile   = /run/fail2ban/fail2ban.pid
          '';
        type = types.string;
        description =
          ''
            The contents of Fail2ban's main configuration file.  It's
            generally not necessary to change it.
          '';
      };

      jails = mkOption {
        default = { };
        example =
          { "apache-nohome-iptables" =
              ''
                # Block an IP address if it accesses a non-existent
                # home directory more than 5 times in 10 minutes,
                # since that indicates that it's scanning.
                filter   = apache-nohome
                action   = iptables-multiport[name=HTTP, port="http,https"]
                logpath  = /var/log/httpd/error_log*
                findtime = 600
                bantime  = 600
                maxretry = 5
              '';
          };
        type = types.attrsOf types.string;
        description =
          ''
            The configuration of each Fail2ban “jail”.  A jail
            consists of an action (such as blocking a port using
            <command>iptables</command>) that is triggered when a
            filter applied to a log file triggers more than a certain
            number of times in a certain time period.  Actions are
            defined in <filename>/etc/fail2ban/action.d</filename>,
            while filters are defined in
            <filename>/etc/fail2ban/filter.d</filename>.
          '';
      };

    };

  };


  ###### implementation

  config = {

    environment.systemPackages = [ pkgs.fail2ban ];

    environment.etc."fail2ban/fail2ban.conf".source = fail2banConf;
    environment.etc."fail2ban/jail.conf".source = jailConf;
    environment.etc."fail2ban/action.d".source = "${pkgs.fail2ban}/etc/fail2ban/action.d/*.conf";
    environment.etc."fail2ban/filter.d".source = "${pkgs.fail2ban}/etc/fail2ban/filter.d/*.conf";

    systemd.services.fail2ban =
      { description = "Fail2ban intrusion prevention system";

        wantedBy = [ "multi-user.target" ];
        after = [ "network.target" ];

        restartTriggers = [ fail2banConf jailConf ];
        path = [ pkgs.fail2ban pkgs.iptables ];

        preStart =
          ''
            mkdir -p /run/fail2ban -m 0755
          '';

        serviceConfig =
          { ExecStart = "${pkgs.fail2ban}/bin/fail2ban-server -f";
            ReadOnlyDirectories = "/";
            ReadWriteDirectories = "/run /var/tmp";
            CapabilityBoundingSet = "CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW";
          };

        postStart =
          ''
            # Wait for the server to start listening.
            for ((n = 0; n < 20; n++)); do
              if fail2ban-client ping; then break; fi
              sleep 0.5
            done

            # Reload its configuration.
            fail2ban-client reload
          '';
      };

    # Add some reasonable default jails.  The special "DEFAULT" jail
    # sets default values for all other jails.
    services.fail2ban.jails.DEFAULT =
      ''
        ignoreip = 127.0.0.1/8
        bantime  = 600
        findtime = 600
        maxretry = 3
        backend  = auto
      '';

    # Block SSH if there are too many failing connection attempts.
    services.fail2ban.jails.ssh-iptables =
      ''
        filter   = sshd
        action   = iptables[name=SSH, port=ssh, protocol=tcp]
        logpath  = /var/log/warn
        maxretry = 5
      '';

  };

}