Ansible Role: fail2ban
An Ansible role for installing and configuring fail2ban on Linux systems. This role provides flexible configuration options for fail2ban's main settings, jail configurations, and custom filters/actions.
Requirements
- Ansible 2.9 or higher
- Target systems: Debian/Ubuntu or RHEL-based distributions
- Python 3 on target hosts
Role Variables
Default Variables
Available variables are listed below, along with default values (see defaults/main.yaml):
# Packages to install
fail2ban_dependencies:
- fail2ban
- python3-systemd
# Service configuration
fail2ban_service: fail2ban
fail2ban_loglevel: INFO
fail2ban_logtarget: /var/log/fail2ban.log
# Default jail settings
fail2ban_ignoreself: "true"
fail2ban_ignoreips:
- 127.0.0.1/8
- ::1
fail2ban_bantime: 10m
fail2ban_findtime: 10m
fail2ban_maxretry: 5
fail2ban_backend: auto
Important Default Settings to Configure
Before deploying to production, consider adjusting these critical settings:
- IP Whitelist (
fail2ban_ignoreips): Add your management IPs to prevent lockouts - Ban Duration (
fail2ban_bantime): Default is 10 minutes; consider longer for production (1h, 24h, 1w) - Max Retry (
fail2ban_maxretry): Default is 5 attempts; lower for stricter security - Find Time Window (
fail2ban_findtime): Default is 10 minutes; adjust based on your threat model - Backend (
fail2ban_backend): Set tosystemdfor systemd-based distros for better performance
Custom Configuration Variables
Using the INI Module Format
You can add custom configuration to fail2ban.local and jail.local by defining options in the INI module format:
# Additional fail2ban.local configuration
fail2ban_configuration: []
- option: loglevel # The INI option name
value: "DEBUG" # The value to set
section: Definition # The INI section
# Additional jail.local configuration
fail2ban_jail_configuration:
- option: destemail
value: "admin@example.com"
section: DEFAULT
- option: sender
value: "fail2ban@example.com"
section: DEFAULT
- option: action
value: "%(action_mwl)s"
section: DEFAULT
INI Format Explanation:
section: The configuration section in the INI file (e.g.,DEFAULT,Definition,sshd)option: The configuration parameter namevalue: The value to assign (must be a string, number, or boolean)
This format allows you to set any fail2ban configuration option without modifying the role itself.
Creating Custom Jails
Method 1: Define Jails as Dictionaries (Recommended for Simple Jails)
Create custom jails by defining them as dictionaries. This method uses a Jinja2 template to generate jail files:
fail2ban_jails:
- name: sshd # Jail name (required)
enabled: true # Enable/disable jail
port: ssh # Service port(s)
logpath: /var/log/auth.log # Log file to monitor
maxretry: 3 # Override default maxretry
bantime: 1h # Override default bantime
findtime: 10m # Override default findtime
banaction: iptables-multiport # Ban action to use
filter: sshd # Filter to use
Common jail parameters:
name: Jail identifier (required)enabled: true/falseport: Service port (ssh, http, https, etc.)filter: Filter name (must exist in filter.d/)logpath: Path to log file(s) to monitormaxretry: Number of failures before banfindtime: Time window for counting failuresbantime: Duration of banbanaction: Action to execute on banaction: Full action with parameters
Method 2: Copy Complete Jail Files (For Complex Configurations)
For more complex jail configurations that require specific options not supported by the template, copy complete jail files:
# Path to directory containing custom jail files
fail2ban_jails_path: "{{ playbook_dir }}/files/fail2ban/jails"
Place your .conf or .local files in the specified directory. They will be copied to /etc/fail2ban/jail.d/.
Custom Filters and Actions
Copying Custom Filters
Define custom filters for application-specific log patterns:
# Path to directory containing custom filter files
fail2ban_filters_path: "{{ playbook_dir }}/files/fail2ban/filters"
Place your filter .conf files in the specified directory. They will be copied to /etc/fail2ban/filter.d/.
Example custom filter (files/fail2ban/filters/myapp.conf):
[Definition]
failregex = ^<HOST> .* "POST /login HTTP/.*" 401
^Authentication failure for .* from <HOST>
ignoreregex =
Copying Custom Actions
Define custom actions for specific ban/unban behaviors:
# Path to directory containing custom action files
fail2ban_actions_path: "files/fail2ban/actions"
Place your action .conf files in the specified directory. They will be copied to /etc/fail2ban/action.d/.
To see an example of a custom action, I've included a ufw-docker action with the role as I use it frequently. It is an enhanced UFW action that provides additional protection for Docker environments. To use it, just set fail2ban_actions_path to actions.
Warning
For this action to work properly, you'll need to configure UFW to work properly with Docker, either manually or using the ufw-docker script.
Dependencies
None.
Example Playbook
Basic Usage with Recommended Defaults
- hosts: servers
become: yes
roles:
- role: fail2ban
vars:
# Add your management IPs to prevent lockouts
fail2ban_ignoreips:
- 127.0.0.1/8
- ::1
- 10.0.0.0/8 # Your private network
# Stricter default settings
fail2ban_bantime: 1h
fail2ban_maxretry: 3
fail2ban_backend: systemd
Custom Configuration with INI Format
The role uses the ini_file module to edit the default configuration files. You may override or add to this configuration:
- hosts: servers
become: yes
roles:
- role: fail2ban
vars:
# Override fail2ban.conf base settings using INI format
fail2ban_configuration:
- option: loglevel
value: "NOTICE"
section: Definition
- option: logtarget
value: "SYSLOG"
section: Definition
# Configure jail.conf email notifications
fail2ban_jail_configuration:
- option: destemail
value: "security@example.com"
section: DEFAULT
- option: sender
value: "fail2ban@example.com"
section: DEFAULT
- option: action
value: "%(action_mwl)s" # Mail with logs
section: DEFAULT
Creating Custom Jails with Dictionaries
- hosts: servers
become: yes
roles:
- role: fail2ban
vars:
fail2ban_bantime: 1h
fail2ban_maxretry: 3
fail2ban_jails:
# SSH protection
- name: sshd
enabled: true
port: ssh
logpath: /var/log/auth.log
maxretry: 3
bantime: 24h
# Nginx authentication failures
- name: nginx-http-auth
enabled: true
port: http,https
logpath: /var/log/nginx/error.log
# Recidive jail for repeat offenders
- name: recidive
enabled: true
maxretry: 3
findtime: 1w
bantime: 30d
logpath: /var/log/fail2ban.log
Using Complete Jail Files for Complex Configurations
- hosts: servers
become: yes
roles:
- role: fail2ban
vars:
# Use dictionaries for simple jails
fail2ban_jails:
- name: sshd
enabled: true
maxretry: 3
# For complex jails, copy complete jail files
fail2ban_jails_path: "{{ playbook_dir }}/files/fail2ban/jails"
Debian-Specific Configuration
SSH Service Name Issue
On Debian systems, there's a common issue where fail2ban's default SSH jail doesn't work out of the box. The problem:
- fail2ban's default configuration expects the service to be named
sshd - On many Debian systems, the actual systemd service is named
ssh.service(notsshd.service) - When using the
systemdbackend, fail2ban looks for logs from thesshdservice and finds nothing - Result: SSH protection silently fails - no errors, but no banning occurs
The Solution
This role provides the fail2ban_default_debian_jail_configuration variable to override Debian's default jail settings:
fail2ban_default_debian_jail_configuration:
- option: backend
value: systemd
section: sshd
- option: journalmatch
value: "_SYSTEMD_UNIT=ssh.service" # Use ssh.service instead of sshd.service
section: sshd
This configuration:
- Explicitly sets the backend to
systemdfor better performance - Corrects the journal match to look for
ssh.serviceinstead of the defaultsshd.service - Is applied only on Debian systems (via
when: ansible_facts['distribution'] == 'Debian')
Usage Example
- hosts: debian_servers
become: yes
roles:
- role: fail2ban
vars:
fail2ban_backend: systemd
# Fix SSH jail on Debian
fail2ban_default_debian_jail_configuration:
- option: backend
value: systemd
section: sshd
- option: journalmatch
value: "_SYSTEMD_UNIT=ssh.service"
section: sshd
fail2ban_jails:
- name: sshd
enabled: true
maxretry: 3
bantime: 1h
Note
This only affects the default SSH jail in
/etc/fail2ban/jail.d/defaults-debian.conf. If you're defining custom SSH jails usingfail2ban_jails, make sure to specify the correctjournalmatchorlogpathfor your system.
Verifying SSH Protection is Working
After applying the role, verify fail2ban is monitoring SSH:
# Check if the sshd jail is active
sudo fail2ban-client status sshd
# Check what logs fail2ban is monitoring
sudo fail2ban-client get sshd logpath
# Test with a failed login and check
sudo fail2ban-client status sshd
If you see "Currently banned: 0" and "Total banned: 0" after several failed login attempts, the jail may not be configured correctly for your system's SSH service name.
Role Tasks
This role performs the following tasks:
- Installs fail2ban and required dependencies
- Configures
fail2ban.localwith base and custom settings - Configures
jail.localwith default jail parameters - Configures Debian-specific jail settings (when applicable)
- Copies custom filter configurations (if provided)
- Copies custom action configurations (if provided)
- Copies or generates jail configurations
- Starts and enables the fail2ban service
Handlers
Restart fail2ban: Restarts the fail2ban service when configuration changes are made
File Organization
Organize your custom files in the following structure:
playbook_directory/
├── files/
│ └── fail2ban/
│ ├── filters/
│ │ ├── myapp.conf
│ │ └── custom-filter.conf
│ ├── actions/
│ │ ├── slack-notify.conf
│ │ └── custom-action.conf
│ └── jails/
│ └── complex-jail.local
├── roles/
│ └── fail2ban/
└── playbook.yml
Tips and Best Practices
- Always whitelist management IPs in
fail2ban_ignoreipsto prevent lockouts - Start with lenient settings (higher maxretry, shorter bantime) and adjust based on logs
- Use systemd backend when available for better performance:
fail2ban_backend: systemd - Monitor fail2ban logs at
/var/log/fail2ban.logto tune your rules - Test custom filters before deploying to production using
fail2ban-regex - Use dictionaries for simple jails, copy files for complex ones requiring specific options
- Keep custom filters and actions in version control alongside your playbooks
Testing Custom Filters
Test your custom filters before deployment:
fail2ban-regex /var/log/myapp.log /etc/fail2ban/filter.d/myapp.conf
License
MIT