#!/usr/bin/env bash # # JbTecWiz Support Centre -- generated fix script # # Fault : fail2ban is not banning, or has banned you # Fix : Point the jail at the right log and filter # Source: https://jbtecwiz.com/support/lnx-sec-fail2ban # # Run as : Root shell # Expect : 30 minutes # Risk : medium # Reversible : yes # # WHEN THIS IS THE RIGHT FIX # Nothing is being banned despite obvious attempts. # # HOW TO UNDO IT # Remove the jail.d file and restart to return to the shipped defaults. # # Walks the fix one step at a time and asks before each. Steps with no # command are yours to do -- it prints those and waits. DRYRUN=1 prints # without executing; UNATTENDED=1 does not ask. # # -------------------------------------------------------------------- # NO WARRANTY - USE AT YOUR OWN RISK # # This script is provided by JbTecWiz as-is and with no warranty of any # kind, express or implied. You run it entirely at your own risk. # # JbTecWiz accepts no liability for any loss or damage arising from its # use, including but not limited to data loss, downtime, or configuration # changes that turn out to be wrong for your system. # # You are responsible for reading this script before running it, for # satisfying yourself that it suits the machine in front of you, and for # having a working backup first. Some steps cannot be undone. # -------------------------------------------------------------------- set -uo pipefail DRYRUN="${DRYRUN:-0}" UNATTENDED="${UNATTENDED:-0}" failed=0 if [ "$(id -u)" -ne 0 ]; then echo " This fix is documented as needing root. Re-run with sudo." >&2 exit 3 fi rule() { printf "\n%s\n" "$(printf '-%.0s' $(seq 1 70))"; if [ $# -gt 0 ]; then echo "$1"; fi; } prose() { echo "$1" | fold -s -w 74 | sed "s/^/ /"; } # Returns 0 when the caller should run the command, 1 when it should not. # A manual step always returns 1 -- there is nothing for the caller to run. step() { # step [command lines...] local n="$1" dotext="$2" why="$3" mode="$4"; shift 4 rule " Step $n of 5" prose "$dotext" if [ -n "$why" ]; then echo; prose "$why"; fi if [ "$mode" = "manual" ]; then echo; echo " -> Do this yourself, then press Enter to carry on." if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r _; fi return 1 fi echo; printf " %s\n" "$@"; echo if [ "$DRYRUN" = "1" ]; then echo " (dry run -- not executed)"; return 1; fi if [ "$UNATTENDED" = "0" ]; then read -r -p " Run this step? [Y]es / [S]kip / [Q]uit " a case "$a" in [Qq]*) echo " Stopped at your request."; exit 0 ;; [Ss]*) echo " Skipped."; return 1 ;; esac fi return 0 } rule echo " fail2ban is not banning, or has banned you" echo " Point the jail at the right log and filter" echo echo " Risk: medium Reversible 30 minutes" echo prose 'No warranty. Use at your own risk - JbTecWiz accepts no liability. Read it before you run it, and have a backup.' rule echo if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r -p " Ready? [y/N] " go case "$go" in [Yy]*) ;; *) echo " Nothing was changed."; exit 0;; esac fi if step 1 'Check the service is running and the jail is enabled.' '' cmd 'systemctl status fail2ban --no-pager' 'sudo fail2ban-client status'; then systemctl status fail2ban --no-pager sudo fail2ban-client status if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 1 failed. The rest of the fix may depend on it." >&2 fi fi if step 2 'Check the backend. On a systemd system with no /var/log/auth.log, a jail using the file backend reads nothing and reports no error.' 'This is the most common cause on current distributions. The jail is enabled, the service is healthy, the filter is correct, and it is watching a file that does not exist.' cmd 'grep -rE '\''^\s*backend|^\s*logpath'\'' /etc/fail2ban/jail.local /etc/fail2ban/jail.d/ 2>/dev/null' 'ls -l /var/log/auth.log /var/log/secure 2>/dev/null'; then grep -rE '^\s*backend|^\s*logpath' /etc/fail2ban/jail.local /etc/fail2ban/jail.d/ 2>/dev/null ls -l /var/log/auth.log /var/log/secure 2>/dev/null if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 2 failed. The rest of the fix may depend on it." >&2 fi fi if step 3 'Set the systemd backend where appropriate.' '' cmd 'sudo tee /etc/fail2ban/jail.d/sshd.local >/dev/null <<'\''EOF'\''' '[sshd]' 'enabled = true' 'backend = systemd' 'maxretry = 5' 'findtime = 10m' 'bantime = 1h' 'EOF' 'sudo systemctl restart fail2ban'; then sudo tee /etc/fail2ban/jail.d/sshd.local >/dev/null <<'EOF' [sshd] enabled = true backend = systemd maxretry = 5 findtime = 10m bantime = 1h EOF sudo systemctl restart fail2ban if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 3 failed. The rest of the fix may depend on it." >&2 fi fi if step 4 'Test the filter against real log lines rather than waiting to see if it works.' 'fail2ban-regex prints how many lines matched. Zero matches with plenty of failures in the log means the filter, not the configuration -- and it takes one command to know which.' cmd 'sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf'; then sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 4 failed. The rest of the fix may depend on it." >&2 fi fi if step 5 'Check the ban action can actually run -- a mismatch between the configured action and the firewall in use fails silently.' '' cmd 'sudo fail2ban-client get sshd actions' 'sudo nft list ruleset | grep -i f2b'; then sudo fail2ban-client get sshd actions sudo nft list ruleset | grep -i f2b if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 5 failed. The rest of the fix may depend on it." >&2 fi fi rule " Confirm it worked" prose 'fail2ban-regex matches real entries and a test failure produces a ban.' if [ "$DRYRUN" = "0" ]; then sudo fail2ban-client status sshd fi rule if [ "$failed" -gt 0 ]; then echo " Finished with $failed failed step(s)." echo " Read the full write-up at https://jbtecwiz.com/support/lnx-sec-fail2ban" else echo " Finished." fi echo prose 'To undo: Remove the jail.d file and restart to return to the shipped defaults.' rule