406 lines
12 KiB
Markdown
406 lines
12 KiB
Markdown
# 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`):
|
|
|
|
```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:
|
|
|
|
1. **IP Whitelist** (`fail2ban_ignoreips`): Add your management IPs to prevent lockouts
|
|
2. **Ban Duration** (`fail2ban_bantime`): Default is 10 minutes; consider longer for production (1h, 24h, 1w)
|
|
3. **Max Retry** (`fail2ban_maxretry`): Default is 5 attempts; lower for stricter security
|
|
4. **Find Time Window** (`fail2ban_findtime`): Default is 10 minutes; adjust based on your threat model
|
|
5. **Backend** (`fail2ban_backend`): Set to `systemd` for 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:
|
|
|
|
```yaml
|
|
# 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 name
|
|
- `value`: 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:
|
|
|
|
```yaml
|
|
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/false
|
|
- `port`: Service port (ssh, http, https, etc.)
|
|
- `filter`: Filter name (must exist in filter.d/)
|
|
- `logpath`: Path to log file(s) to monitor
|
|
- `maxretry`: Number of failures before ban
|
|
- `findtime`: Time window for counting failures
|
|
- `bantime`: Duration of ban
|
|
- `banaction`: Action to execute on ban
|
|
- `action`: 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:
|
|
|
|
```yaml
|
|
# 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:
|
|
|
|
```yaml
|
|
# 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`):
|
|
```ini
|
|
[Definition]
|
|
failregex = ^<HOST> .* "POST /login HTTP/.*" 401
|
|
^Authentication failure for .* from <HOST>
|
|
ignoreregex =
|
|
```
|
|
|
|
#### Copying Custom Actions
|
|
|
|
Define custom actions for specific ban/unban behaviors:
|
|
|
|
```yaml
|
|
# 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](files/actions/ufw-docker.conf) 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](https://github.com/chaifeng/ufw-docker) script.
|
|
|
|
## Dependencies
|
|
|
|
None.
|
|
|
|
## Example Playbook
|
|
|
|
### Basic Usage with Recommended Defaults
|
|
|
|
```yaml
|
|
- 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:
|
|
|
|
```yaml
|
|
- 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
|
|
|
|
```yaml
|
|
- 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
|
|
|
|
```yaml
|
|
- 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` (not `sshd.service`)
|
|
- When using the `systemd` backend, fail2ban looks for logs from the `sshd` service 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:
|
|
```yaml
|
|
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 `systemd` for better performance
|
|
- Corrects the journal match to look for `ssh.service` instead of the default `sshd.service`
|
|
- Is applied only on Debian systems (via `when: ansible_facts['distribution'] == 'Debian'`)
|
|
|
|
### Usage Example
|
|
```yaml
|
|
- 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 using `fail2ban_jails`, make sure to specify the correct `journalmatch` or `logpath` for your system.
|
|
|
|
### Verifying SSH Protection is Working
|
|
|
|
After applying the role, verify fail2ban is monitoring SSH:
|
|
```bash
|
|
# 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:
|
|
|
|
1. Installs fail2ban and required dependencies
|
|
2. Configures `fail2ban.local` with base and custom settings
|
|
3. Configures `jail.local` with default jail parameters
|
|
4. Configures Debian-specific jail settings (when applicable)
|
|
5. Copies custom filter configurations (if provided)
|
|
6. Copies custom action configurations (if provided)
|
|
7. Copies or generates jail configurations
|
|
8. 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
|
|
|
|
1. **Always whitelist management IPs** in `fail2ban_ignoreips` to prevent lockouts
|
|
2. **Start with lenient settings** (higher maxretry, shorter bantime) and adjust based on logs
|
|
3. **Use systemd backend** when available for better performance: `fail2ban_backend: systemd`
|
|
4. **Monitor fail2ban logs** at `/var/log/fail2ban.log` to tune your rules
|
|
5. **Test custom filters** before deploying to production using `fail2ban-regex`
|
|
6. **Use dictionaries for simple jails**, copy files for complex ones requiring specific options
|
|
7. **Keep custom filters and actions in version control** alongside your playbooks
|
|
|
|
## Testing Custom Filters
|
|
|
|
Test your custom filters before deployment:
|
|
|
|
```bash
|
|
fail2ban-regex /var/log/myapp.log /etc/fail2ban/filter.d/myapp.conf
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|