summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2020-01-23 05:33:17 +0100
committerGuilhem Moulin <guilhem@fripost.org>2020-01-25 01:57:05 +0100
commitee4e9e9836ad05279647b04eb1e8a3a4b0e16568 (patch)
treed4e566a7b535f7d62e4fd6fd1a521ea6d7563d21
parent7641a5d5d152db349082b1d0ec93a40888b2ef8e (diff)
Improve/harden fail2ban configuration.
* Use nftables sets with a timeout * Start daemon with a hardened unit file and restricted Capability Bounding Set. (This requires to change the log path to /var/log/fail2ban/*.) * Skip database as we don't care about persistence. * Refactor jail.local
-rw-r--r--roles/common/files/etc/fail2ban/action.d/nftables-allports.local16
-rw-r--r--roles/common/files/etc/fail2ban/fail2ban.local20
-rw-r--r--roles/common/files/etc/fail2ban/filter.d/nextcloud.conf6
-rw-r--r--roles/common/files/etc/fail2ban/filter.d/roundcube.conf16
-rw-r--r--roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf18
-rw-r--r--roles/common/tasks/fail2ban.yml68
-rw-r--r--roles/common/templates/etc/fail2ban/jail.local.j289
7 files changed, 135 insertions, 98 deletions
diff --git a/roles/common/files/etc/fail2ban/action.d/nftables-allports.local b/roles/common/files/etc/fail2ban/action.d/nftables-allports.local
new file mode 100644
index 0000000..3c8c030
--- /dev/null
+++ b/roles/common/files/etc/fail2ban/action.d/nftables-allports.local
@@ -0,0 +1,16 @@
+[Definition]
+# No need to create sets and rules, these are defined globally in nftables.conf
+actionstart =
+actionstop =
+actioncheck =
+
+# unbanning is taken care of by setting a timeout on the nft set already
+actionunban =
+
+[Init]
+# With banaction = *-allports there is no need for separate rule names
+set_name = fail2ban
+blocktype = drop
+
+[Init?family=inet6]
+set_name = fail2ban6
diff --git a/roles/common/files/etc/fail2ban/fail2ban.local b/roles/common/files/etc/fail2ban/fail2ban.local
new file mode 100644
index 0000000..53cba35
--- /dev/null
+++ b/roles/common/files/etc/fail2ban/fail2ban.local
@@ -0,0 +1,20 @@
+[Definition]
+
+# Option: logtarget
+# Notes.: Set the log target. This could be a file, SYSLOG, STDERR or STDOUT.
+# Only one log target can be specified.
+# If you change logtarget from the default value and you are
+# using logrotate -- also adjust or disable rotation in the
+# corresponding configuration file
+# (e.g. /etc/logrotate.d/fail2ban on Debian systems)
+# Values: [ STDOUT | STDERR | SYSLOG | SYSOUT | FILE ] Default: STDERR
+#
+logtarget = /var/log/fail2ban/fail2ban.log
+
+# Options: dbfile
+# Notes.: Set the file for the fail2ban persistent data to be stored.
+# A value of ":memory:" means database is only stored in memory
+# and data is lost when fail2ban is stopped.
+# A value of "None" disables the database.
+# Values: [ None :memory: FILE ] Default: /var/lib/fail2ban/fail2ban.sqlite3
+dbfile = None
diff --git a/roles/common/files/etc/fail2ban/filter.d/nextcloud.conf b/roles/common/files/etc/fail2ban/filter.d/nextcloud.conf
new file mode 100644
index 0000000..22305d6
--- /dev/null
+++ b/roles/common/files/etc/fail2ban/filter.d/nextcloud.conf
@@ -0,0 +1,6 @@
+# Source: https://github.com/nextcloud/vm/blob/master/apps/fail2ban.sh
+
+[Definition]
+failregex=(?:^{|,)\"message\":\"Login failed: <F-USER>.*?</F-USER> \(Remote IP: '<HOST>'\)\"(:?,|}$)
+ (?:^{|,)\"message\":\"Login failed: <F-USER>.*?</F-USER> \(Remote IP: <HOST>\)\"(:?,|}$)
+ (?:^{|,)\"remoteAddr\":\"<HOST>\",.*Trusted domain error
diff --git a/roles/common/files/etc/fail2ban/filter.d/roundcube.conf b/roles/common/files/etc/fail2ban/filter.d/roundcube.conf
deleted file mode 100644
index c8cb5d3..0000000
--- a/roles/common/files/etc/fail2ban/filter.d/roundcube.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-[Definition]
-
-# Option: failregex
-# Notes.: regex to match the password failures messages in the logfile. The
-# host must be matched by a group named "host". The tag "<HOST>" can
-# be used for standard IP/hostname matching and is only an alias for
-# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
-# Values: TEXT
-#
-failregex = IMAP Error: Login failed for \S+ from <HOST>\. AUTHENTICATE \S+: Authentication failed\.
-
-# Option: ignoreregex
-# Notes.: regex to ignore. If this regex matches, the line is ignored.
-# Values: TEXT
-#
-ignoreregex =
diff --git a/roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf b/roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf
new file mode 100644
index 0000000..e3e651f
--- /dev/null
+++ b/roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf
@@ -0,0 +1,18 @@
+[Unit]
+After=nftables.service
+
+[Service]
+# Need explicit rights to read logs as we don't grant CAP_DAC_READ_SEARCH
+SupplementaryGroups=adm
+
+# Hardening
+NoNewPrivileges=yes
+ProtectSystem=strict
+ReadWriteDirectories=/var/log/fail2ban
+RuntimeDirectory=fail2ban
+PrivateDevices=yes
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_NETLINK
+CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
diff --git a/roles/common/tasks/fail2ban.yml b/roles/common/tasks/fail2ban.yml
index 84e6b7a..89427ea 100644
--- a/roles/common/tasks/fail2ban.yml
+++ b/roles/common/tasks/fail2ban.yml
@@ -1,37 +1,79 @@
- name: Install fail2ban
apt: pkg=fail2ban
-- name: Configure fail2ban
+# Log into a dedicate directory so we can use ReadWriteDirectories in
+# the .service file
+- name: Create directory /var/log/fail2ban
+ file: path=/var/log/fail2ban
+ state=directory
+ owner=root group=adm
+ mode=0750
+
+- name: Fix fail2ban logrotate snippet
+ lineinfile: dest=/etc/logrotate.d/fail2ban
+ state=present
+ line="/var/log/fail2ban/*.log"
+ insertbefore="^[^#]*\\s{$"
+ tags:
+ - logrotate
+
+- name: Configure fail2ban (fail2ban.local)
+ copy: src=etc/fail2ban/fail2ban.local
+ dest=/etc/fail2ban/fail2ban.local
+ owner=root group=root
+ mode=0644
+ register: r1
+ notify:
+ - Restart fail2ban
+
+- name: Configure fail2ban (jail.local)
template: src=etc/fail2ban/jail.local.j2
dest=/etc/fail2ban/jail.local
owner=root group=root
mode=0644
- register: r1
+ register: r2
notify:
- Restart fail2ban
-- name: Add roundcube filter
- copy: src=etc/fail2ban/filter.d/roundcube.conf
- dest=/etc/fail2ban/filter.d/roundcube.conf
+- name: Configure fail2ban (action.d/nftables-allports.local)
+ copy: src=etc/fail2ban/action.d/nftables-allports.local
+ dest=/etc/fail2ban/action.d/nftables-allports.local
owner=root group=root
mode=0644
- register: r2
- when: "'webmail' in group_names"
+ register: r3
notify:
- Restart fail2ban
-- name: Add dovecot filter
- copy: src=etc/fail2ban/filter.d/dovecot.conf
- dest=/etc/fail2ban/filter.d/dovecot.conf
+- name: Copy filters
+ copy: src=etc/fail2ban/filter.d/
+ dest=/etc/fail2ban/filter.d/
owner=root group=root
mode=0644
- register: r3
- when: "'IMAP' in group_names"
+ register: r4
+ notify:
+ - Restart fail2ban
+
+- name: Create directory /etc/systemd/system/fail2ban.service.d/override.conf
+ file: path=/etc/systemd/system/fail2ban.service.d
+ state=directory
+ owner=root group=root
+ mode=0750
+
+- name: Harden fail2ban.service
+ copy: src=etc/systemd/system/fail2ban.service.d/override.conf
+ dest=/etc/systemd/system/fail2ban.service.d/override.conf
+ owner=root group=root
+ mode=0644
+ register: r5
notify:
+ - systemctl daemon-reload
- Restart fail2ban
- name: Start fail2ban
service: name=fail2ban state=started
- when: not (r1.changed or r2.changed or r3.changed)
+ when: not (r1.changed or r2.changed or r3.changed or r4.changed or r5.changed)
- meta: flush_handlers
+
+- name: Delete /var/lib/fail2ban/fail2ban.sqlite3
+ file: path=/var/lib/fail2ban/fail2ban.sqlite3 state=absent
diff --git a/roles/common/templates/etc/fail2ban/jail.local.j2 b/roles/common/templates/etc/fail2ban/jail.local.j2
index 618fbd7..29b004c 100644
--- a/roles/common/templates/etc/fail2ban/jail.local.j2
+++ b/roles/common/templates/etc/fail2ban/jail.local.j2
@@ -7,87 +7,38 @@
# jail.{conf,local} configuration files.
destemail = admin@fripost.org
-# Specify chain where jumps would need to be added in iptables-* actions
-chain = fail2ban
+# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
+# will not ban a host which matches an address in this list. Several addresses
+# can be defined using space (and/or comma) separator.
+ignoreip = 127.0.0.0/8, ::1, {{ ipsec_subnet }}
-# Choose default action.
-action = %(action_)s
-
-# Don't ban ourselves.
-ignoreip = 127.0.0.0/8 {{ ipsec_subnet }}
+banaction = nftables-allports
+logpath = /var/log/fail2ban/fail2ban.log
#
# JAILS
#
-[ssh]
-
-enabled = true
-port = {{ ansible_port|default('22') }}
-filter = sshd
-logpath = /var/log/auth.log
-maxretry = 5
-
-[ssh-ddos]
-
-enabled = true
-port = {{ ansible_port|default('22') }}
-filter = sshd-ddos
-logpath = /var/log/auth.log
-maxretry = 2
-
-
-# Generic filter for pam. Has to be used with action which bans all ports
-# such as iptables-allports, shorewall
-[pam-generic]
-
-enabled = true
-# pam-generic filter can be customized to monitor specific subset of 'tty's
-filter = pam-generic
-# port actually must be irrelevant but lets leave it all for some possible uses
-port = anyport
-banaction = iptables-allports
-logpath = /var/log/auth.log
-maxretry = 6
+[sshd]
+enabled = true
-{% if 'MX' in group_names %}
[postfix]
+enabled = {{ 'MX' in group_names }}
-enabled = true
-port = smtp
-filter = postfix
-logpath = /var/log/mail.log
-maxretry = 10
-{% endif %}
-
-
-{% if 'IMAP' in group_names %}
[dovecot]
+enabled = {{ 'IMAP' in group_names }}
-enabled = true
-port = imap2,imaps,pop3,pop3s,sieve
-filter = dovecot
-logpath = /var/log/mail.log
-{% endif %}
-
-
-{% if 'MSA' in group_names %}
-[sasl]
-
-enabled = true
-port = submission,submissions
-filter = postfix-sasl
-logpath = /var/log/mail.warn
-{% endif %}
-
+[postfix-sasl]
+enabled = {{ 'MSA' in group_names }}
-{% if 'webmail' in group_names %}
-[roundcube]
+[roundcube-auth]
+enabled = {{ 'webmail' in group_names }}
+# XXX Bullseye: logpath = /var/log/roundcube/errors.log
-enabled = true
-port = http,https
-filter = roundcube
-logpath = /var/log/roundcube/errors
-{% endif %}
+[nextcloud]
+enabled = {{ 'nextcloud' in group_names }}
+port = http,https
+filter = nextcloud
+logpath = /var/log/nextcloud/nextcloud.log
# vim: set filetype=dosini :