Study Note: macOS Server - fail2ban



Configuring Fail2Ban on macOS Silicon

Fail2Ban is a crucial security tool that helps protect your server from various types of brute force and malicious attacks by monitoring log files and banning IPs that show suspicious behavior.

Introduction to Fail2Ban

Fail2Ban is an intrusion prevention software framework that protects computer servers from brute-force attacks. It works by scanning log files and banning IPs that exhibit malicious behaviors, such as too many password failures, seeking for exploits, etc.

Installation and Basic Setup

Installation Steps

1. Install Fail2Ban using Homebrew:

brew install fail2ban

2. Directory Structure:

Configuration

Copy the Default Configuration File

Create a local copy of the default configuration file.

sudo cp /usr/local/etc/fail2ban/jail.conf /usr/local/etc/fail2ban/jail.local

Configure Jail for SSH

Open the jail.local file and enable the SSH jail by adding or modifying the following section:

[sshd]
      enabled = true
      port = ssh
      filter = sshd
      logpath = /var/log/auth.log
      maxretry = 5

Configure Jail for NGINX

Separated Configuration [Choice 1 of 2]

You can add separate sections for monitoring authentication errors and access logs if they are for different types of issues or combine them if you want a unified approach. Here's an example configuration that includes both log files:

    [nginx-http-auth]
    enabled = true
    port = http,https
    filter = nginx-http-auth
    logpath = /opt/homebrew/etc/nginx/error.log
    maxretry = 3
    bantime = 3600

    [nginx-access]
    enabled = true
    port = http,https
    filter = nginx-access
    logpath = /opt/homebrew/etc/nginx/access.log
    maxretry = 5
    bantime = 3600
  

Filter Definitions

nginx-http-auth Filter:
Create or edit the filter file /opt/homebrew/etc/fail2ban/filter.d/nginx-http-auth.conf to match patterns related to authentication issues.

Example filter configuration for nginx-http-auth:

    [Definition]
    failregex = ^<HOST> - .* "GET .* HTTP/.*" 401 .*
    ignoreregex =
  

nginx-access Filter:
Create or edit the filter file /opt/homebrew/etc/fail2ban/filter.d/nginx-access.conf to match patterns related to access issues.

Example filter configuration for nginx-access:

    [Definition]
    failregex = ^<HOST> - .* "GET .* HTTP/.*" 404 .*
    ignoreregex =
  

Combined Configuration [Choice 2 of 2]

If you prefer to combine the monitoring of both logs under a single section, you can specify multiple log paths in the logpath directive. Here’s an example:

    [nginx]
    enabled = true
    port = http,https
    filter = nginx
    logpath = /opt/homebrew/etc/nginx/error.log /opt/homebrew/etc/nginx/access.log
    maxretry = 5
    bantime = 3600
  

Combined Filter Definition

Create or edit the filter file /opt/homebrew/etc/fail2ban/filter.d/nginx.conf to include patterns from both error.log and access.log.

Example combined filter configuration for nginx:

    [Definition]
    failregex = ^<HOST> - .* "GET .* HTTP/.*" 401 .*  # Unauthorized access
    ^<HOST> - .* "GET .* HTTP/.*" 404 .*  # Not found
    ignoreregex =
  

Advanced Configuration

Persistent Bans

To make bans persistent across reboots, add the following:

[DEFAULT]
      bantime = -1

Ensure bans persist across reboots by using a database.

dbfile = /var/lib/fail2ban/fail2ban.sqlite3

Whitelist Trusted IPs

To whitelist certain IPs, add:

ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

Avoid banning trusted IPs.

ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

Custom Filters

Create custom filters by defining regex patterns:

Custom filter file: /usr/local/etc/fail2ban/filter.d/custom.conf

[Definition]
      failregex = <custom-regex-pattern>

Custom Actions

Create custom actions to integrate with other security tools or logging systems.

action = %(action_mwl)s

Integration with Firewalls

Integrate Fail2Ban with your firewall, e.g., pf on macOS:

[DEFAULT]
      banaction = pf

Rate-Limiting and SSH Specifics

Invalid User Attempts:

[sshd-invalid]
      enabled = true
      logpath = /var/log/auth.log
      filter = sshd-invalid
      maxretry = 3

Non-standard Port:

[sshd]
      port = 2222

Brute-force Detection:

[sshd]
      enabled = true
      logpath = /var/log/auth.log
      maxretry = 5

NGINX Specifics

404 Error Pattern:

[nginx-404]
      enabled = true
      logpath = /opt/homebrew/etc/nginx/access.log
      maxretry = 10

Multiple Failed Login Attempts:

[nginx-login]
      enabled = true
      logpath = /opt/homebrew/etc/nginx/error.log
      maxretry = 3

SQL Injection Attempts:

[nginx-sqli]
      enabled = true
      logpath = /opt/homebrew/etc/nginx/error.log
      maxretry = 1
      filter = nginx-sqli

Granular Ban Settings

Define ban times and retry limits:

[DEFAULT]
      bantime = 1h
      findtime = 10m
      maxretry = 3

Granular Ban Settings

Ban Time: Duration for which an IP is banned.

bantime = 3600  # 1 hour

Find Time: Time window within which maxretry attempts are counted.

findtime = 600  # 10 minutes

Max Retry: Number of attempts allowed before banning.

maxretry = 5

Custom Actions

Define custom actions in /usr/local/etc/fail2ban/action.d/:

Create custom.conf:

[Definition]
      actionstart = <custom-start-command>
      actionstop = <custom-stop-command>
      actioncheck = <custom-check-command>



Starting and Managing Fail2Ban

Start Fail2Ban

sudo fail2ban-client start

Enable Fail2Ban at Startup

To ensure Fail2Ban starts at boot, create a LaunchDaemon. Save the following as /Library/LaunchDaemons/com.fail2ban.plist:

<?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
      <dict>
      <key>Label</key>
      <string>com.fail2ban</string>
      <key>ProgramArguments</key>
      <array>
      <string>/usr/local/bin/fail2ban-client</string>
      <string>start</string>
      </array>
      <key>RunAtLoad</key>
      <true/>
      <key>KeepAlive</key>
      <true/>
      </dict>
      </plist>

Load the Daemon

sudo launchctl load /Library/LaunchDaemons/com.fail2ban.plist



Monitoring and Logs

Check Fail2Ban Status

sudo fail2ban-client status

Check Specific Jail Status

sudo fail2ban-client status sshd
      sudo fail2ban-client status nginx-http-auth

Unban an IP

sudo fail2ban-client set sshd unbanip <IP_ADDRESS>

View Logs

Check Fail2Ban logs:

tail -f /usr/local/var/log/fail2ban.log

Restart Fail2Ban

sudo brew services restart fail2ban



Core Components

Jails

Definition: A jail specifies the combination of a filter and an action.

Configuration: Jails are defined in the configuration file (/usr/local/etc/fail2ban/jail.conf or /usr/local/etc/fail2ban/jail.local).

Example:

[sshd]
      enabled = true
      port = ssh
      filter = sshd
      logpath = /var/log/auth.log
      maxretry = 5
      bantime = 3600

Filters

Definition: Filters define the patterns to search for in log files.

Location: Filters are stored in the /usr/local/etc/fail2ban/filter.d/ directory.

Example:

[Definition]
      failregex = ^<HOST> - .* "GET .* HTTP/.*" 404 .*
      ignoreregex =

Actions

Definition: Actions define what to do when a filter catches an event.

Common Actions: Banning an IP via iptables, sending email notifications, etc.

Example:

action = iptables[name=HTTP, port=http, protocol=tcp]



Extending Fail2Ban

Custom Filters

Create custom filters for unique log patterns. Create a file in /etc/fail2ban/filter.d/custom.conf:

[Definition]
      failregex = <CUSTOM_REGEX>
      ignoreregex =

Integration with Firewalls

Integrate Fail2Ban with firewalls like iptables or pf to enhance security:

[DEFAULT]
      banaction = iptables-multiport

Rate Limiting

Implement rate limiting to mitigate abuse:

[http-get-dos]
      enabled = true
      port = http,https
      filter = http-get-dos
      logpath = /var/log/nginx/access.log
      maxretry = 300
      findtime = 300
      bantime = 600

      action = iptables[name=HTTP, port=http, protocol=tcp]



Custom Patterns for SSH

SSH Invalid User Attempts

[ssh-invalid-user]
      enabled = true
      filter = sshd-invalid-user
      logpath = /var/log/auth.log
      maxretry = 3
      bantime = 3600

      [Definition]
      failregex = ^<HOST> .* Invalid user .*$

      ignoreregex =

SSH Connection Attempts with Non-Standard Port

[ssh-non-standard-port]
      enabled = true
      filter = sshd-non-standard-port
      logpath = /var/log/auth.log
      maxretry = 3
      bantime = 3600

      [Definition]
      failregex = ^<HOST> .* Failed password for .* from <HOST> port [^22].*$

      ignoreregex =

SSH Brute-Force Detection

[ssh-brute-force]
      enabled = true
      filter = sshd-brute-force
      logpath = /var/log/auth.log
      maxretry = 5
      bantime = 3600

      [Definition]
      failregex = ^<HOST> .* Received disconnect from <HOST>: 3: .* Too many authentication failures for .*$

      ignoreregex =



Custom Patterns for NGINX

NGINX 404 Error Pattern

[nginx-404-errors]
      enabled = true
      filter = nginx-404
      logpath = /opt/homebrew/etc/nginx/access.log
      maxretry = 10
      bantime = 3600

      [Definition]
      failregex = ^<HOST> - .* "GET .* HTTP/.*" 404 .*$

      ignoreregex =

NGINX Multiple Failed Login Attempts

[nginx-login-fail]
      enabled = true
      filter = nginx-login-fail
      logpath = /opt/homebrew/etc/nginx/error.log
      maxretry = 5
      bantime = 3600

      [Definition]
      failregex = ^<HOST> - .* "POST /login.*" 401 .*$

      ignoreregex =

NGINX SQL Injection Attempts

[nginx-sql-injection]
      enabled = true
      filter = nginx-sql-injection
      logpath = /opt/homebrew/etc/nginx/access.log
      maxretry = 1
      bantime = 86400

      [Definition]
      failregex = ^<HOST> - .* "GET .*select.*from.* HTTP/.*" 403 .*$

      ignoreregex =