├── .ansible-lint ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .yamllint ├── Dockerfile ├── LICENSE.txt ├── README.md ├── Vagrantfile ├── defaults └── main.yml ├── files └── empty ├── handlers └── main.yml ├── meta └── main.yml ├── molecule └── default │ ├── collections.yml │ ├── converge.yml │ ├── molecule.yml │ ├── prepare.yml │ └── verify.yml ├── requirements.yml ├── tasks └── main.yml ├── templates └── etc │ └── fail2ban │ ├── fail2ban.local.j2 │ └── jail.local.j2 ├── tests ├── inventory ├── test.yml └── vagrant.yml └── vars └── main.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | warn_list: 3 | - role-name 4 | - name[play] 5 | - name[casing] 6 | - '303' 7 | - '405' 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 'on': 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | schedule: 9 | - cron: '30 1 * * 3' 10 | 11 | jobs: 12 | 13 | lint: 14 | name: Lint 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Check out the codebase 18 | uses: actions/checkout@v3 19 | 20 | - name: Set up Python 3 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: '3.x' 24 | 25 | - name: Install test dependencies 26 | run: | 27 | pip install ansible-lint 28 | ansible-galaxy install -r requirements.yml 29 | 30 | - name: Lint code 31 | run: | 32 | yamllint . 33 | ansible-lint 34 | 35 | molecule: 36 | name: Molecule 37 | runs-on: ubuntu-latest 38 | defaults: 39 | run: 40 | working-directory: "${{ github.repository }}" 41 | needs: 42 | - lint 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | include: 47 | - distro: debian10 48 | ansible-version: '>=9, <10' 49 | - distro: debian11 50 | - distro: debian12 51 | - distro: ubuntu1804 52 | ansible-version: '>=9, <10' 53 | - distro: ubuntu2004 54 | - distro: ubuntu2204 55 | - distro: ubuntu2404 56 | 57 | steps: 58 | - name: Check out the codebase 59 | uses: actions/checkout@v3 60 | with: 61 | path: "${{ github.repository }}" 62 | 63 | - name: Set up Python 3 64 | uses: actions/setup-python@v4 65 | with: 66 | python-version: '3.x' 67 | 68 | - name: Install test dependencies 69 | run: | 70 | pip install 'ansible${{ matrix.ansible-version }}' molecule-plugins[docker] docker 71 | - name: Run Molecule tests 72 | run: | 73 | molecule test 74 | env: 75 | ANSIBLE_FORCE_COLOR: '1' 76 | ANSIBLE_VERBOSITY: '2' 77 | MOLECULE_DEBUG: '1' 78 | MOLECULE_DISTRO: "${{ matrix.distro }}" 79 | PY_COLORS: '1' 80 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release 3 | 'on': 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | 10 | release: 11 | name: Release 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check out the codebase 15 | uses: actions/checkout@v3 16 | 17 | - name: Publish to Galaxy 18 | uses: robertdebock/galaxy-action@1.2.0 19 | with: 20 | galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | ###################### 3 | .DS_Store 4 | .DS_Store? 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | Icon? 9 | ehthumbs.db 10 | Thumbs.db 11 | 12 | # IDE files # 13 | ################# 14 | /.settings 15 | /.buildpath 16 | /.project 17 | /nbproject 18 | *.komodoproject 19 | *.kpf 20 | /.idea 21 | 22 | # Vagrant files # 23 | .virtualbox/ 24 | .vagrant/ 25 | vagrant_ansible_inventory_* 26 | ansible.cfg 27 | 28 | # Other files # 29 | ############### 30 | !empty 31 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | braces: 6 | max-spaces-inside: 1 7 | level: error 8 | brackets: 9 | max-spaces-inside: 1 10 | level: error 11 | line-length: disable 12 | truthy: disable 13 | 14 | ignore: | 15 | .tox/ 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | MAINTAINER Mischa ter Smitten 3 | 4 | ENV LANG C.UTF-8 5 | ENV LC_ALL C.UTF-8 6 | 7 | # python 8 | RUN apt-get update && \ 9 | DEBIAN_FRONTEND=noninteractive apt-get install -y python3-minimal python3-dev curl && \ 10 | apt-get clean 11 | RUN curl -sL https://bootstrap.pypa.io/pip/3.6/get-pip.py | python3 - 12 | RUN rm -rf $HOME/.cache 13 | 14 | # ansible 15 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python3-apt && \ 16 | apt-get clean 17 | RUN pip3 install ansible==2.10.7 18 | RUN rm -rf $HOME/.cache 19 | 20 | # provision 21 | COPY . /etc/ansible/roles/ansible-role 22 | WORKDIR /etc/ansible/roles/ansible-role 23 | RUN ansible-playbook -i tests/inventory tests/test.yml --connection=local 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Oefenweb.nl 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fail2ban 2 | 3 | [![CI](https://github.com/Oefenweb/ansible-fail2ban/workflows/CI/badge.svg)](https://github.com/Oefenweb/ansible-fail2ban/actions?query=workflow%3ACI) 4 | [![Ansible Galaxy](http://img.shields.io/badge/ansible--galaxy-fail2ban-blue.svg)](https://galaxy.ansible.com/Oefenweb/fail2ban) 5 | 6 | Set up fail2ban in Debian-like systems. 7 | 8 | ## Requirements 9 | 10 | None 11 | 12 | ## Variables 13 | 14 | - `fail2ban_loglevel`: [default: `3`, or `INFO` in newer versions]: Sets the loglevel output (e.g. `1 = ERROR`, `2 = WARN`, `3 = INFO`, `4 = DEBUG`) 15 | - `fail2ban_logtarget`: [default: `/var/log/fail2ban.log`]: Sets the log target. This could be a file, SYSLOG, STDERR or STDOUT 16 | - `fail2ban_syslog_target`: [default: `/var/log/fail2ban.log`]: 17 | - `fail2ban_syslog_facility`: [default: `1`]: 18 | - `fail2ban_socket`: [default: `/var/run/fail2ban/fail2ban.sock`]: Sets the socket file, which is used to communicate with the daemon 19 | - `fail2ban_pidfile`: [default: `/var/run/fail2ban/fail2ban.pid`]: Sets the pid file, which is used to to store the process ID of the daemon (Only works on `fail2ban >= 0.8.9`) 20 | - `fail2ban_dbpurgeage`: [default: `86400`]: Sets age at which bans should be purged from the database 21 | 22 | - `fail2ban_ignoreips`: [default: `[127.0.0.1/8]`]: Which IP address/CIDR mask/DNS host should be ignored from fail2ban's actions 23 | - `fail2ban_bantime`: [default: `600`]: Sets the bantime 24 | - `fail2ban_maxretry`: [default: `3`]: Maximum number of retries before the host is put into jail 25 | - `fail2ban_findtime`: [default: `600`]: A host is banned if it has generated `fail2ban_maxretry` during the last `fail2ban_findtime` 26 | - `fail2ban_backend`: [default: `auto`]: Specifies the backend used to get files modification. For Debian 12, `systemd` is required 27 | - `fail2ban_banaction`: [default: `iptables-multiport`]: Sets the global/default banaction 28 | - `fail2ban_banaction_allports`: [default: `iptables-allports`]: Sets the global/default banaction for allports 29 | - `fail2ban_mta`: [default: `sendmail`]: Email action 30 | - `fail2ban_protocol`: [default: `tcp`]: Sets the default protocol 31 | - `fail2ban_chain`: [default: `INPUT`]: Specifies the chain where jumps would need to be added in iptables-* actions 32 | - `fail2ban_action`: [default: `%(action_)s`]: Default action. **Note that variables (including the actions defined elsewhere in the config files) must be wrapped in python-style `%(` and `)s` so they are expanded** 33 | - `fail2ban_sendername`: [default: `Fail2ban`]: The 'from' name for emails sent by mta actions. NB: Use `fail2ban_sender` to set the 'from' email address. 34 | - `fail2ban_sender`: [optional]: The 'from' address for emails sent by mta actions. 35 | - `fail2ban_filterd_path`: [optional]: Path to directory containing filters to copy (**note the trailing slash**) 36 | - `fail2ban_actiond_path`: [optional]: Path to directory containing actions to copy (**note the trailing slash**) 37 | - `fail2ban_jaild_path`: [optional]: Path to directory containing jails to copy (**note the trailing slash**) 38 | 39 | - `fail2ban_services` [default see `defaults/main.yml`]: Service definitions 40 | - `fail2ban_services.{n}.name` [required]: Service name (e.g. `ssh`) 41 | - `fail2ban_services.{n}.enabled` [default: `true`]: Whether or not enabled 42 | - `fail2ban_services.{n}.*` [optional]: Name of the option 43 | - `fail2ban_services.{n}.*.*` [optional]: Value of the option 44 | 45 | ### For version >= 0.11.1 46 | 47 | - `fail2ban_bantime_increment`: [default: `true`]: Increases bantime after being banned before 48 | - `fail2ban_bantime_factor`: [default: `1`]: Bantime increase factor for `bantime_formula` or `bantime_multipliers` 49 | - `fail2ban_bantime_formula`: [default: `'ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor'`]: Formula that will be used to calculate the increased bantime. **Note that you can either use `bantime_formula` or `bantime_multipliers` while `bantime_multipliers` takes precedence.** 50 | - `fail2ban_bantime_overalljails`: [default: `false`]: Ban IPs for all jails if multiple are defined 51 | - `fail2ban_bantime_rndtime`: [optional]: Option for smart bots that try to access after the bantime immediately 52 | - `fail2ban_bantime_multipliers`: [optional]: Multiplier to use instead of bantime_formula. For example `1 2 4 8 16 32 64`. **Note for bantime = 600 and bantime_factor=1 this would be `600*1*1, 600*1*2...`** 53 | 54 | ## Dependencies 55 | 56 | None 57 | 58 | ## Example(s) 59 | 60 | ### Simple 61 | 62 | ```yaml 63 | --- 64 | - hosts: all 65 | roles: 66 | - oefenweb.fail2ban 67 | ``` 68 | 69 | ### Enable sshd filter (with non-default settings) 70 | 71 | ```yaml 72 | --- 73 | - hosts: all 74 | roles: 75 | - oefenweb.fail2ban 76 | vars: 77 | fail2ban_services: 78 | # In older versions of Fail2Ban this is called ssh 79 | - name: sshd 80 | port: 2222 81 | maxretry: 5 82 | bantime: -1 83 | ``` 84 | 85 | ### Add custom filters (from outside the role) 86 | 87 | ```yaml 88 | --- 89 | - hosts: all 90 | roles: 91 | - oefenweb.fail2ban 92 | vars: 93 | fail2ban_filterd_path: ../../../files/fail2ban/etc/fail2ban/filter.d/ 94 | fail2ban_services: 95 | - name: apache-wordpress-logins 96 | port: http,https 97 | filter: apache-wordpress-logins 98 | logpath: /var/log/apache2/access.log 99 | maxretry: 5 100 | findtime: 120 101 | ``` 102 | 103 | ## License 104 | 105 | MIT 106 | 107 | ## Author Information 108 | 109 | Mischa ter Smitten (based on work of [ANXS](https://github.com/ANXS)) 110 | 111 | ## Feedback, bug-reports, requests, ... 112 | 113 | Are [welcome](https://github.com/Oefenweb/ansible-fail2ban/issues)! 114 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby ts=2 sw=2 tw=0 et : 3 | 4 | role = File.basename(File.expand_path(File.dirname(__FILE__))) 5 | 6 | boxes = [ 7 | { 8 | :name => "ubuntu-1804", 9 | :box => "bento/ubuntu-18.04", 10 | :ip => '10.0.0.13', 11 | :cpu => "50", 12 | :ram => "384" 13 | }, 14 | { 15 | :name => "ubuntu-2004", 16 | :box => "bento/ubuntu-20.04", 17 | :ip => '10.0.0.14', 18 | :cpu => "50", 19 | :ram => "512" 20 | }, 21 | { 22 | :name => "ubuntu-2204", 23 | :box => "bento/ubuntu-22.04", 24 | :ip => '10.0.0.15', 25 | :cpu => "50", 26 | :ram => "512" 27 | }, 28 | { 29 | :name => "ubuntu-2404", 30 | :box => "bento/ubuntu-24.04", 31 | :ip => '10.0.0.16', 32 | :cpu => "50", 33 | :ram => "512" 34 | }, 35 | { 36 | :name => "debian-10", 37 | :box => "bento/debian-10", 38 | :ip => '10.0.0.18', 39 | :cpu => "50", 40 | :ram => "256" 41 | }, 42 | { 43 | :name => "debian-11", 44 | :box => "bento/debian-11", 45 | :ip => '10.0.0.19', 46 | :cpu => "50", 47 | :ram => "256" 48 | }, 49 | { 50 | :name => "debian-12", 51 | :box => "bento/debian-12", 52 | :ip => '10.0.0.20', 53 | :cpu => "50", 54 | :ram => "384" 55 | }, 56 | ] 57 | 58 | Vagrant.configure("2") do |config| 59 | boxes.each do |box| 60 | config.vm.define box[:name] do |vms| 61 | vms.vm.box = box[:box] 62 | vms.vm.hostname = "ansible-#{role}-#{box[:name]}" 63 | 64 | vms.vm.provider "virtualbox" do |v| 65 | v.customize ["modifyvm", :id, "--cpuexecutioncap", box[:cpu]] 66 | v.customize ["modifyvm", :id, "--memory", box[:ram]] 67 | end 68 | 69 | vms.vm.network :private_network, ip: box[:ip] 70 | 71 | vms.vm.provision :ansible do |ansible| 72 | ansible.playbook = "tests/vagrant.yml" 73 | ansible.verbose = "vv" 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | # defaults file 2 | --- 3 | fail2ban_loglevel: "{{ 'INFO' if (ansible_distribution == 'Ubuntu' and ansible_distribution_major_version is version('16', '>=') or ansible_distribution == 'Debian' and ansible_distribution_major_version is version('9', '>=')) else '3' }}" 4 | fail2ban_logtarget: /var/log/fail2ban.log 5 | fail2ban_syslog_target: /var/log/fail2ban.log 6 | fail2ban_syslog_facility: 1 7 | fail2ban_socket: /var/run/fail2ban/fail2ban.sock 8 | fail2ban_pidfile: /var/run/fail2ban/fail2ban.pid 9 | fail2ban_dbpurgeage: 86400 10 | 11 | fail2ban_sendername: 'Fail2ban' 12 | 13 | fail2ban_ignoreips: 14 | - 127.0.0.1/8 15 | - ::1 16 | 17 | fail2ban_bantime: 600 18 | fail2ban_bantime_increment: true 19 | fail2ban_bantime_factor: 1 20 | fail2ban_bantime_formula: 'ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor' 21 | fail2ban_bantime_overalljails: false 22 | 23 | fail2ban_maxretry: 3 24 | fail2ban_findtime: 600 25 | fail2ban_backend: auto 26 | fail2ban_destemail: root@localhost 27 | fail2ban_banaction: iptables-multiport 28 | fail2ban_banaction_allports: iptables-allports 29 | fail2ban_mta: sendmail 30 | fail2ban_protocol: tcp 31 | fail2ban_chain: INPUT 32 | fail2ban_action: '%(action_)s' 33 | 34 | fail2ban_services: 35 | - name: "{{ 'sshd' if (ansible_distribution == 'Ubuntu' and ansible_distribution_major_version is version('16', '>=') or ansible_distribution == 'Debian' and ansible_distribution_major_version is version('9', '>=')) else 'ssh' }}" 36 | -------------------------------------------------------------------------------- /files/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oefenweb/ansible-fail2ban/dab56b2f99a2b7474f24db30131e6da909b13709/files/empty -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | # handlers file 2 | --- 3 | - name: restart fail2ban 4 | ansible.builtin.service: 5 | name: fail2ban 6 | state: restarted 7 | when: service_default_state | default('started') == 'started' 8 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | # meta file 2 | --- 3 | galaxy_info: 4 | author: oefenweb 5 | role_name: fail2ban 6 | company: Oefenweb.nl B.V. 7 | description: Set up fail2ban in Debian-like systems 8 | license: MIT 9 | min_ansible_version: 2.10.0 10 | platforms: 11 | - name: Ubuntu 12 | versions: 13 | - bionic 14 | - focal 15 | - jammy 16 | - noble 17 | - name: Debian 18 | versions: 19 | - buster 20 | - bullseye 21 | - bookworm 22 | galaxy_tags: 23 | - system 24 | - networking 25 | dependencies: [] 26 | -------------------------------------------------------------------------------- /molecule/default/collections.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: [] 3 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | become: true 5 | roles: 6 | - ../../../ 7 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | driver: 5 | name: docker 6 | platforms: 7 | - name: instance 8 | image: "geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2004}-ansible:latest" 9 | command: ${MOLECULE_DOCKER_COMMAND:-""} 10 | volumes: 11 | - /sys/fs/cgroup:/sys/fs/cgroup:rw 12 | - /var/lib/containerd 13 | cgroupns_mode: host 14 | privileged: true 15 | pre_build_image: true 16 | provisioner: 17 | name: ansible 18 | playbooks: 19 | prepare: prepare.yml 20 | converge: converge.yml 21 | verify: verify.yml 22 | -------------------------------------------------------------------------------- /molecule/default/prepare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Prepare 3 | hosts: all 4 | become: true 5 | tasks: [] 6 | -------------------------------------------------------------------------------- /molecule/default/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Verify 3 | hosts: all 4 | become: true 5 | tasks: [] 6 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | # requirements file 2 | --- 3 | collections: [] 4 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | # tasks file 2 | --- 3 | - name: install 4 | ansible.builtin.apt: 5 | name: "{{ ' '.join(fail2ban_dependencies).split() }}" 6 | state: "{{ apt_install_state | default('latest') }}" 7 | update_cache: true 8 | cache_valid_time: "{{ apt_update_cache_valid_time | default(3600) }}" 9 | tags: 10 | - configuration 11 | - fail2ban 12 | - fail2ban-install 13 | 14 | - name: get fail2ban version 15 | ansible.builtin.command: > 16 | fail2ban-server -V 17 | changed_when: false 18 | check_mode: false 19 | register: _fail2ban_version_raw 20 | tags: 21 | - configuration 22 | - fail2ban 23 | - fail2ban-install 24 | 25 | - name: register fail2ban version 26 | ansible.builtin.set_fact: 27 | fail2ban_version: "{{ _fail2ban_version_raw.stdout | regex_search('([0-9]+\\.[0-9]+\\.[0-9]+)') }}" 28 | changed_when: false 29 | check_mode: false 30 | tags: 31 | - configuration 32 | - fail2ban 33 | - fail2ban-install 34 | 35 | - name: remove configuration file - /etc/fail2ban/jail.d/defaults-debian.conf 36 | ansible.builtin.file: 37 | state: absent 38 | path: /etc/fail2ban/jail.d/defaults-debian.conf 39 | notify: restart fail2ban 40 | tags: 41 | - configuration 42 | - fail2ban 43 | - fail2ban-configuration 44 | - fail2ban-configuration-delete 45 | 46 | - name: update configuration file - /etc/fail2ban/fail2ban.local 47 | ansible.builtin.template: 48 | src: etc/fail2ban/fail2ban.local.j2 49 | dest: /etc/fail2ban/fail2ban.local 50 | owner: root 51 | group: root 52 | mode: '0644' 53 | notify: restart fail2ban 54 | tags: 55 | - configuration 56 | - fail2ban 57 | - fail2ban-configuration 58 | - fail2ban-configuration-update 59 | 60 | - name: update configuration file - /etc/fail2ban/jail.local 61 | ansible.builtin.template: 62 | src: etc/fail2ban/jail.local.j2 63 | dest: /etc/fail2ban/jail.local 64 | owner: root 65 | group: root 66 | mode: '0644' 67 | notify: restart fail2ban 68 | tags: 69 | - configuration 70 | - fail2ban 71 | - fail2ban-configuration 72 | - fail2ban-configuration-update 73 | 74 | - name: copy filters 75 | ansible.builtin.copy: 76 | src: "{{ fail2ban_filterd_path }}" 77 | dest: /etc/fail2ban/filter.d/ 78 | owner: root 79 | group: root 80 | mode: '0644' 81 | when: fail2ban_filterd_path is defined 82 | notify: restart fail2ban 83 | tags: 84 | - configuration 85 | - fail2ban 86 | - fail2ban-filters 87 | 88 | - name: copy actions 89 | ansible.builtin.copy: 90 | src: "{{ fail2ban_actiond_path }}" 91 | dest: /etc/fail2ban/action.d/ 92 | owner: root 93 | group: root 94 | mode: '0644' 95 | when: fail2ban_actiond_path is defined 96 | notify: restart fail2ban 97 | tags: 98 | - configuration 99 | - fail2ban 100 | - fail2ban-actions 101 | 102 | - name: copy jails 103 | ansible.builtin.copy: 104 | src: "{{ fail2ban_jaild_path }}" 105 | dest: /etc/fail2ban/jail.d/ 106 | owner: root 107 | group: root 108 | mode: '0644' 109 | when: fail2ban_jaild_path is defined 110 | notify: restart fail2ban 111 | tags: 112 | - configuration 113 | - fail2ban 114 | - fail2ban-jails 115 | 116 | - name: start and enable service 117 | ansible.builtin.service: 118 | name: fail2ban 119 | state: "{{ service_default_state | default('started') }}" 120 | enabled: "{{ service_default_enabled | default(true) | bool }}" 121 | tags: 122 | - configuration 123 | - fail2ban 124 | - fail2ban-start-enable-service 125 | -------------------------------------------------------------------------------- /templates/etc/fail2ban/fail2ban.local.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_managed | comment }} 2 | 3 | # Overrides values from the fail2ban.conf configuration file. 4 | # 5 | # For comments relating to each setting see fail2ban.conf 6 | 7 | [Definition] 8 | 9 | loglevel = {{ fail2ban_loglevel }} 10 | logtarget = {{ fail2ban_logtarget }} 11 | 12 | {% if fail2ban_logtarget == "SYSLOG" %} 13 | syslog-target = {{ fail2ban_syslog_target }} 14 | syslog-facility = {{ fail2ban_syslog_facility }} 15 | {% endif %} 16 | 17 | socket = {{ fail2ban_socket }} 18 | 19 | pidfile = {{ fail2ban_pidfile }} 20 | 21 | dbpurgeage = {{ fail2ban_dbpurgeage }} 22 | -------------------------------------------------------------------------------- /templates/etc/fail2ban/jail.local.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_managed | comment }} 2 | 3 | # Fail2Ban local configuration file. 4 | # Overrides changes in the main jail file, /etc/fail2ban/jail.conf 5 | # Use this file to change local settings. 6 | 7 | [DEFAULT] 8 | 9 | {% if fail2ban_version is version('0.11.1', '>=') %} 10 | bantime.increment = {{ fail2ban_bantime_increment | bool | to_json }} 11 | {% if fail2ban_bantime_rndtime is defined %} 12 | bantime.rndtime = {{ fail2ban_bantime_rndtime }} 13 | {% endif %} 14 | {% if fail2ban_bantime_maxtime is defined %} 15 | bantime.maxtime = {{ fail2ban_bantime_maxtime }} 16 | {% endif %} 17 | bantime.factor = {{ fail2ban_bantime_factor }} 18 | {% if fail2ban_bantime_multipliers is not defined %} 19 | bantime.formula = {{ fail2ban_bantime_formula }} 20 | {% endif %} 21 | {% if fail2ban_bantime_multipliers is defined %} 22 | bantime.multipliers = {{ fail2ban_bantime_multipliers }} 23 | {% endif %} 24 | bantime.overalljails = {{ fail2ban_bantime_overalljails | bool | to_json }} 25 | {% endif %} 26 | 27 | # "ignoreip" can be an IP address, a CIDR mask or a DNS host 28 | ignoreip = {{ fail2ban_ignoreips | join(' ') }} 29 | bantime = {{ fail2ban_bantime }} 30 | maxretry = {{ fail2ban_maxretry }} 31 | findtime = {{ fail2ban_findtime }} 32 | 33 | # "backend" specifies the backend used to get files modification. Available 34 | # options are "gamin", "polling" and "auto". 35 | # yoh: For some reason Debian shipped python-gamin didn't work as expected 36 | # This issue left ToDo, so polling is default backend for now 37 | backend = {{ fail2ban_backend }} 38 | 39 | # 40 | # Destination email address used solely for the interpolations in 41 | # jail.{conf,local} configuration files. 42 | destemail = {{ fail2ban_destemail }} 43 | 44 | # 45 | # Sender name and email address used solely for the interpolations in 46 | # jail.{conf,local} configuration files. 47 | sendername = {{ fail2ban_sendername }} 48 | {% if fail2ban_sender is defined %} 49 | sender = {{ fail2ban_sender }} 50 | {% endif %} 51 | 52 | # 53 | # ACTIONS 54 | # 55 | 56 | # Default banning action (e.g. iptables, iptables-new, 57 | # iptables-multiport, shorewall, etc) It is used to define 58 | # action_* variables. Can be overridden globally or per 59 | # section within jail.local file 60 | banaction = {{ fail2ban_banaction }} 61 | banaction_allports = {{ fail2ban_banaction_allports }} 62 | 63 | # email action. Since 0.8.1 upstream fail2ban uses sendmail 64 | # MTA for the mailing. Change mta configuration parameter to mail 65 | # if you want to revert to conventional 'mail'. 66 | mta = {{ fail2ban_mta }} 67 | 68 | # Default protocol 69 | protocol = {{ fail2ban_protocol }} 70 | 71 | # Specify chain where jumps would need to be added in iptables-* actions 72 | chain = {{ fail2ban_chain }} 73 | 74 | # 75 | # Action shortcuts. To be used to define action parameter 76 | 77 | # The simplest action to take: ban only 78 | action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] 79 | 80 | # ban & send an e-mail with whois report to the destemail. 81 | action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] 82 | %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] 83 | 84 | # ban & send an e-mail with whois report and relevant log lines 85 | # to the destemail. 86 | action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] 87 | %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] 88 | 89 | # Choose default action. To change, just override value of 'action' with the 90 | # interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local 91 | # globally (section [DEFAULT]) or per specific section 92 | action = {{ fail2ban_action }} 93 | 94 | # 95 | # JAILS 96 | # 97 | 98 | # Next jails corresponds to the standard configuration in Fail2ban 0.6 which 99 | # was shipped in Debian. Enable any defined here jail by including 100 | # 101 | # [SECTION_NAME] 102 | # enabled = true 103 | 104 | # 105 | # in /etc/fail2ban/jail.local. 106 | # 107 | # Optionally you may override any other parameter (e.g. banaction, 108 | # action, port, logpath, etc) in that section within jail.local 109 | 110 | 111 | {% for service in fail2ban_services %} 112 | [{{ service.name }}] 113 | enabled = {{ service.enabled | default(true) | bool | to_json }} 114 | {% for option, value in service.items() | sort %} 115 | {% if option not in ['name', 'enabled'] %} 116 | {{ option }} = {{ value }} 117 | {% endif %} 118 | {% endfor %} 119 | 120 | {% endfor %} 121 | -------------------------------------------------------------------------------- /tests/inventory: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | # test file 2 | --- 3 | - name: converge 4 | hosts: localhost 5 | connection: local 6 | become: true 7 | roles: 8 | - ../../ 9 | -------------------------------------------------------------------------------- /tests/vagrant.yml: -------------------------------------------------------------------------------- 1 | # test file 2 | --- 3 | - name: converge 4 | hosts: all 5 | remote_user: vagrant 6 | become: true 7 | roles: 8 | - ../../ 9 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | # vars file 2 | --- 3 | fail2ban_dependencies: 4 | - fail2ban 5 | - "{{ (fail2ban_backend == 'systemd') | ternary('python' + (ansible_python_version is version('3', '>=') | ternary('3', '')) + '-systemd', '') }}" 6 | --------------------------------------------------------------------------------