From da8b8305340dad74df912b600b9b71321a20ac16 Mon Sep 17 00:00:00 2001 From: Pratik Tripathy <> Date: Mon, 13 Oct 2025 13:35:03 +0530 Subject: [PATCH] fix(fail2ban): Multiple fixes - fix: quotes removed from `emptylog` in jail.local - refactor: Remove separate fn for Linux fail2ban - fix: Check fail2ban config validity before starting the service - fix: FreeBSD: enable fail2ban before starting the service --- init-linux-harden.sh | 301 ++++++++++++++++++++----------------------- 1 file changed, 140 insertions(+), 161 deletions(-) diff --git a/init-linux-harden.sh b/init-linux-harden.sh index 7fe466d..219212b 100755 --- a/init-linux-harden.sh +++ b/init-linux-harden.sh @@ -1,7 +1,7 @@ #!/bin/sh SCRIPT_NAME=server-init-harden -SCRIPT_VERSION=3.1 +SCRIPT_VERSION=3.7 TIMESTAMP=$(date '+%Y-%m-%d-%H-%M-%S') LOG_FILE_NAME="/var/log/${SCRIPT_NAME}_${TIMESTAMP}.log" @@ -731,133 +731,6 @@ configure_firewall() { fi } -fail2ban_jail_settings() { - JAIL_LOCAL=$1 - - # Backup jail.local if it exists - if [ -f "$JAIL_LOCAL" ]; then - JAIL_LOCAL_BACKUP="${JAIL_LOCAL}.bak.${TIMESTAMP}" - cp "$JAIL_LOCAL" "$JAIL_LOCAL_BACKUP" - file_log "INFO" "Created backup of existing jail.local at $JAIL_LOCAL_BACKUP" - fi - - # Get server's public IP - file_log "Getting server's public IP..." - PUBLIC_IP=$(curl -s -4 --max-time 10 --fail https://ifconfig.me 2>&1) - file_log "INFO" "Server public IP: $PUBLIC_IP" - - file_log "INFO" "Adding jails to $JAIL_LOCAL..." - - cat <"$JAIL_LOCAL" -[DEFAULT] -backend = auto -banaction = firewallcmd-rich-rules[actiontype=] -banaction_allports = firewallcmd-rich-rules[actiontype=] -ignoreip = 127.0.0.1/8 ::1 $PUBLIC_IP -bantime = 1h -findtime = 10m -maxretry = 5 -# Action: ban only (action_) or ban and email (action_mwl) -action = %(action_)s - -# -# SSH Jail -# -[sshd] -enabled = true -port = ssh -filter = sshd -logpath = %(sshd_log)s - /var/log/auth.log - /var/log/secure -maxretry = 5 -bantime = 1h -findtime = 10m - -# -# Nginx Bot Search - Blocks bots searching for vulnerabilities (404 errors) -# -[nginx-botsearch] -enabled = true -port = http,https -filter = nginx-botsearch -logpath = %(nginx_access_log)s - /var/log/nginx/access.log - $(dirname "$JAIL_LOCAL_BACKUP")/emptylog -maxretry = 5 -bantime = 6h -findtime = 10m - -# -# Nginx HTTP Authentication -# -[nginx-http-auth] -enabled = true -port = http,https -filter = nginx-http-auth -logpath = %(nginx_error_log)s - /var/log/nginx/error.log - $(dirname "$JAIL_LOCAL_BACKUP")/emptylog -maxretry = 3 -bantime = 6h -findtime = 10m - -# -# Nginx Limit Request (DDoS protection) -# -[nginx-limit-req] -enabled = true -port = http,https -filter = nginx-limit-req -logpath = %(nginx_error_log)s - /var/log/nginx/error.log - $(dirname "$JAIL_LOCAL_BACKUP")/emptylog -maxretry = 10 -bantime = 6h -findtime = 10m - -# -# HAProxy HTTP Authentication Failures -# -[haproxy-http-auth] -enabled = true -port = http,https -filter = haproxy-http-auth -logpath = /var/log/haproxy.log - /var/log/haproxy/haproxy.log - /var/log/haproxy/*.log - $(dirname "$JAIL_LOCAL_BACKUP")/emptylog -maxretry = 3 -bantime = 6h -findtime = 10m - -# -# Recidive Jail - Ban repeat offenders -# This jail monitors fail2ban.log for IPs that have been banned multiple times -# -[recidive] -enabled = true -filter = recidive -logpath = /var/log/fail2ban.log -banaction = %(banaction_allports)s -bantime = 1w -findtime = 1d -maxretry = 3 -EOF - - # FreeBSD specific ban-actions - if [ -f /etc/pf.conf ]; then - sed -i.bak -E 's/(^banaction = )firewallcmd.*/\1pf[actiontype=]/' "$JAIL_LOCAL" - sed -i.bak -E 's/(^banaction_allports = )firewallcmd.*/\1pf[actiontype=]/' "$JAIL_LOCAL" - rm "$JAIL_LOCAL".bak >/dev/null 2>&1 - fi - - # Dummy logfile so the configuration doesn't fail - touch "$(dirname "$JAIL_LOCAL")"/emptylog && chmod 644 "$(dirname "$JAIL_LOCAL")"/emptylog - - file_log "INFO" "Jails added to $JAIL_LOCAL" -} - revert_fail2ban_jail_file() { if [ -f "$JAIL_LOCAL_BACKUP" ]; then console_log "INFO" "Reverting jail.local using [ $JAIL_LOCAL_BACKUP ]..." @@ -885,19 +758,142 @@ revert_fail2ban_jail_file() { console_log "INFO" "Restarted fail2ban with original configuration" file_log "INFO" "Restarted fail2ban with original configuration" else + manage_service fail2ban disable console_log "ERROR" "Failed to restart fail2ban service even with original configuration" file_log "ERROR" "Failed to restart fail2ban service even with original configuration" return 1 fi } -configure_fail2ban_linux() { - fail2ban_jail_settings "/etc/fail2ban/jail.local" +fail2ban_jail_settings() { + JAIL_LOCAL=$1 + + # Backup jail.local if it exists + if [ -f "$JAIL_LOCAL" ]; then + JAIL_LOCAL_BACKUP="${JAIL_LOCAL}.bak.${TIMESTAMP}" + cp "$JAIL_LOCAL" "$JAIL_LOCAL_BACKUP" + file_log "INFO" "Created backup of existing jail.local at $JAIL_LOCAL_BACKUP" + fi + + # Get server's public IP + file_log "Getting server's public IP..." + PUBLIC_IP=$(curl -s -4 --max-time 10 --fail https://ifconfig.me 2>&1) + file_log "INFO" "Server public IP: $PUBLIC_IP" + + # Dummy logfile so the configuration doesn't fail when nginx/haproxy are not installed + JAIL_LOCAL_DIR=$(dirname "$JAIL_LOCAL") + touch "$JAIL_LOCAL_DIR"/emptylog && chmod 644 "$JAIL_LOCAL_DIR"/emptylog + + file_log "INFO" "Adding jails to $JAIL_LOCAL..." + + cat <"$JAIL_LOCAL" +[DEFAULT] +backend = auto +banaction = firewallcmd-rich-rules[actiontype=] +banaction_allports = firewallcmd-rich-rules[actiontype=] +ignoreip = 127.0.0.1/8 ::1 $PUBLIC_IP +bantime = 1h +findtime = 10m +maxretry = 5 +# Action: ban only (action_) or ban and email (action_mwl) +action = %(action_)s + +# +# SSH Jail +# +[sshd] +enabled = true +port = ssh +filter = sshd +logpath = %(sshd_log)s + /var/log/auth.log + /var/log/secure +maxretry = 5 +bantime = 1h + +# +# Nginx Bot Search - Blocks bots searching for vulnerabilities (404 errors) +# +[nginx-botsearch] +enabled = true +port = http,https +filter = nginx-botsearch +logpath = %(nginx_access_log)s + $JAIL_LOCAL_DIR/emptylog +maxretry = 5 +bantime = 6h + +# +# Nginx HTTP Authentication +# +[nginx-http-auth] +enabled = true +port = http,https +filter = nginx-http-auth +logpath = %(nginx_error_log)s + $JAIL_LOCAL_DIR/emptylog +maxretry = 3 +bantime = 6h + +# +# Nginx Limit Request (DDoS protection) +# +[nginx-limit-req] +enabled = true +port = http,https +filter = nginx-limit-req +logpath = %(nginx_error_log)s + $JAIL_LOCAL_DIR/emptylog +maxretry = 10 +bantime = 6h + +# +# HAProxy HTTP Authentication Failures +# +[haproxy-http-auth] +enabled = true +port = http,https +filter = haproxy-http-auth +logpath = /var/log/haproxy.log + /var/log/haproxy/haproxy.log + /var/log/haproxy/*.log + $JAIL_LOCAL_DIR/emptylog +maxretry = 3 +bantime = 6h + +# +# Recidive Jail - Ban repeat offenders +# This jail monitors fail2ban.log for IPs that have been banned multiple times +# +[recidive] +enabled = true +filter = recidive +logpath = /var/log/fail2ban.log + $JAIL_LOCAL_DIR/emptylog +banaction = %(banaction_allports)s +bantime = 1w +findtime = 1d +maxretry = 3 +EOF + + # FreeBSD specific ban-actions + if [ -f /etc/pf.conf ]; then + sed -i.bak -E 's/(^banaction = )firewallcmd.*/\1pf[actiontype=]/' "$JAIL_LOCAL" + sed -i.bak -E 's/(^banaction_allports = )firewallcmd.*/\1pf[actiontype=]/' "$JAIL_LOCAL" + rm "$JAIL_LOCAL".bak >/dev/null 2>&1 + fi + + file_log "INFO" "Jails added to $JAIL_LOCAL" + + output=$(fail2ban-client -t 2>&1 && manage_service fail2ban enable && manage_service fail2ban start) + command_status=$? + + file_log "INFO" "$output" # Restart fail2ban - if ! manage_service fail2ban restart; then # Error in configuration - console_log "ERROR" "Failed to restart fail2ban service" - file_log "ERROR" "Failed to restart fail2ban service" + if [ $command_status -ne 0 ]; then + console_log "ERROR" "Failed to start fail2ban service" + file_log "ERROR" "Failed to start fail2ban service" revert_fail2ban_jail_file @@ -905,32 +901,10 @@ configure_fail2ban_linux() { fi } -configure_fail2ban_freebsd() { - RC_CONF_FILE="/etc/rc.conf" +fail2ban_freebsd_pf_conf() { PF_CONF_FILE="/etc/pf.conf" - fail2ban_jail_settings "/usr/local/etc/fail2ban/jail.local" - - # Auto start fail2ban on boot and restart with new configuration - output=$(sysrc fail2ban_enable="YES" 2>&1 && manage_service fail2ban restart 2>&1) - command_output=$? - - file_log "INFO" "$output" - - # Revert fail2ban & rc.conf changes if fail2ban starting failed - if [ $command_output -ne 0 ]; then - file_log "ERROR" "Could not start fail2ban service. Reverting changes..." - - # Don't start fail2ban on boot - sed -i.bak '/^fail2ban_enable/d' $RC_CONF_FILE - rm "$RC_CONF_FILE".bak >/dev/null 2>&1 - - file_log "INFO" "Reverted $RC_CONF_FILE" - - revert_fail2ban_jail_file - - return 1 - fi + # Backup the pf configuration file if [ -f "$PF_CONF_FILE" ]; then PF_CONF_BACKUP_FILE="${PF_CONF_FILE}.bak.${TIMESTAMP}" output=$(cp "$PF_CONF_FILE" "$PF_CONF_BACKUP_FILE" 2>&1) @@ -954,7 +928,7 @@ EOF command_status=$? file_log "INFO" "$output" - if [ $command_output -ne 0 ]; then + if [ $command_status -ne 0 ]; then console_log "ERROR" "Failed to restart pf post fail2ban. Reverting pf.config..." file_log "ERROR" "Failed to restart pf post fail2ban. Reverting pf.config..." @@ -985,11 +959,16 @@ configure_fail2ban() { file_log "INFO" "Configuring Fail2ban..." if command -v firewall-cmd >/dev/null 2>&1; then # Linux - configure_fail2ban_linux + fail2ban_jail_settings "/etc/fail2ban/jail.local" command_status=$? elif [ -f /etc/pf.conf ]; then # FreeBSD - configure_fail2ban_freebsd - command_status=$? + if fail2ban_jail_settings "/usr/local/etc/fail2ban/jail.local"; then + # Perform additional pf specific configuration + fail2ban_freebsd_pf_conf + command_status=$? + else + command_status=1 + fi fi if [ "$command_status" -eq 0 ]; then