diff --git a/roles/fail2ban/README.md b/roles/fail2ban/README.md new file mode 100644 index 0000000..2b0066e --- /dev/null +++ b/roles/fail2ban/README.md @@ -0,0 +1,26 @@ +# Fail2ban + +Bans brute-force sources via UFW. Reads logs from the systemd journal (`backend = systemd`), so it works on both Arch and Debian. + +## Jails + +- `sshd` +- `nginx-http-auth` + +## Notes + +- Logs to the journal (`logtarget = STDOUT` in `fail2ban.local`) — see `journalctl -u fail2ban`. +- The systemd unit is hardened (`ProtectSystem=strict`); the drop-in lives at `/etc/systemd/system/fail2ban.service.d/override.conf` and is fully managed by the role. +- Firewall/banaction is UFW on every host; jails ban via `ufw prepend reject`. + +## Variables + +See [defaults/main.yml](defaults/main.yml). + +## Verify + +```bash +sudo fail2ban-client status +sudo fail2ban-client set sshd banip 192.0.2.1 && sudo ufw status | grep 192.0.2.1 +sudo fail2ban-client set sshd unbanip 192.0.2.1 +``` diff --git a/roles/fail2ban/handlers/main.yml b/roles/fail2ban/handlers/main.yml new file mode 100644 index 0000000..a53ce03 --- /dev/null +++ b/roles/fail2ban/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Restart fail2ban + ansible.builtin.systemd: + name: fail2ban + daemon_reload: true + state: restarted diff --git a/roles/fail2ban/tasks/main.yml b/roles/fail2ban/tasks/main.yml index 6346ab7..6606235 100644 --- a/roles/fail2ban/tasks/main.yml +++ b/roles/fail2ban/tasks/main.yml @@ -13,6 +13,13 @@ mode: "0700" recurse: true +- name: Deploy fail2ban main config override (log to journald) + ansible.builtin.template: + src: fail2ban.local.j2 + dest: /etc/fail2ban/fail2ban.local + mode: "0600" + notify: Restart fail2ban + - name: Install Fail2ban Config block: - name: General configuration @@ -31,10 +38,6 @@ - name: Service hardening (read-only root rights) block: - - name: Check if hardening configuration is already applied - ansible.builtin.stat: - path: /etc/systemd/system/fail2ban.service.d/override.conf - register: override_conf - name: Create configuration directory ansible.builtin.file: path: /etc/systemd/system/fail2ban.service.d @@ -42,15 +45,15 @@ owner: root group: root mode: "0700" + - name: Apply hardening configuration ansible.builtin.template: src: hardened.fail2ban.conf.j2 dest: /etc/systemd/system/fail2ban.service.d/override.conf - when: not override_conf.stat.exists - - name: Reload systemd - ansible.builtin.systemd: - daemon_reload: true - when: not override_conf.stat.exists + owner: root + group: root + mode: "0644" + notify: Restart fail2ban - name: Enable UFW community.general.ufw: diff --git a/roles/fail2ban/templates/fail2ban.local.j2 b/roles/fail2ban/templates/fail2ban.local.j2 new file mode 100644 index 0000000..707f163 --- /dev/null +++ b/roles/fail2ban/templates/fail2ban.local.j2 @@ -0,0 +1,2 @@ +[DEFAULT] +logtarget = STDOUT diff --git a/roles/fail2ban/templates/hardened.fail2ban.conf.j2 b/roles/fail2ban/templates/hardened.fail2ban.conf.j2 index bb6f1bc..26162e9 100644 --- a/roles/fail2ban/templates/hardened.fail2ban.conf.j2 +++ b/roles/fail2ban/templates/hardened.fail2ban.conf.j2 @@ -3,9 +3,11 @@ PrivateDevices=yes PrivateTmp=yes ProtectHome=read-only ProtectSystem=strict -ReadWritePaths=-/var/run/fail2ban +RuntimeDirectory=fail2ban +RuntimeDirectoryMode=0750 ReadWritePaths=-/var/lib/fail2ban -ReadWritePaths=-/var/log/fail2ban.log ReadWritePaths=-/var/spool/postfix/maildrop ReadWritePaths=-/run/xtables.lock +ReadWritePaths=-/etc/ufw +ReadWritePaths=-/var/lib/ufw CapabilityBoundingSet=CAP_AUDIT_READ CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW