├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── Vagrantfile ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── services_examples.md ├── tasks └── main.yml ├── templates ├── fail2ban.conf.j2 └── jail.conf.j2 ├── test.yml └── vagrant-inventory /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | Icon 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | .vagrant 9 | test 10 | .#* 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | python: "2.7" 4 | before_install: 5 | - sudo apt-get update -qq 6 | - sudo apt-get install -qq python-apt python-pycurl 7 | install: 8 | - pip install ansible==2.2.0.0 9 | script: 10 | - echo localhost > inventory 11 | - ansible-playbook -i inventory test.yml --syntax-check 12 | - ansible-playbook -i inventory test.yml --connection=local --sudo 13 | - > 14 | ansible-playbook -i inventory test.yml --connection=local --sudo 15 | | grep -q 'changed=0.*failed=0' 16 | && (echo 'Idempotence test: pass' && exit 0) 17 | || (echo 'Idempotence test: fail' && exit 1) 18 | 19 | notifications: 20 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014 Pieterjan Vandaele 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ANXS - fail2ban [![Build Status](https://travis-ci.org/ANXS/fail2ban.png)](https://travis-ci.org/ANXS/fail2ban) 2 | 3 | Ansible role which installs and configures fail2ban, a utility that watches logs for failed login attempts and blocks repeat offenders with firewall rules. 4 | 5 | 6 | #### Requirements & Dependencies 7 | - Tested on Ansible 1.4 or higher. 8 | 9 | 10 | #### Variables 11 | 12 | - `fail2ban_loglevel` - sets the loglevel output (1 = ERROR, 2 = WARN, 3 = INFO, 4 = DEBUG; default is 3) 13 | - `fail2ban_logtarget1` - set the log target. This could be a file, SYSLOG, STDERR or STDOUT 14 | - `fail2ban_syslog_target` 15 | - `fail2ban_syslog_facility` 16 | - `fail2ban_socket` - sets the socket file, which is used to communicate with the daemon 17 | 18 | - `fail2ban_ignoreip` - which IP address/CIDR mask/DNS host should be ignored from fail2ban's actions 19 | - `fail2ban_bantime` - sets the bantime 20 | - `fail2ban_maxretry` - maximum number of retries before the host is put into jail 21 | - `fail2ban_backend` - specifies the backend used to get files modification 22 | - `fail2ban_email` - email address which can be used in the interpolation of the `fail2ban_services` 23 | - `fail2ban_banaction` - sets the global/default banaction (can be overriden on a per role basis) 24 | - `fail2ban_mta` - email action 25 | - `fail2ban_protocol` - sets the default protocol 26 | - `fail2ban_chain` - specifies the chain where jumps would need to be added in iptables-* actions 27 | - `fail2ban_action` - default action 28 | 29 | For each of the services you wish to protect/put a jail or ban up for, you need to add it to the `fail2ban_services` list of hashes: 30 | 31 | ```yaml 32 | fail2ban_services: 33 | - name: "ssh" 34 | enabled: "true" 35 | port: "ssh" 36 | filter: "sshd" 37 | logpath: "/var/log/auth.log" 38 | maxretry: 6 39 | protocol: "tcp" (optional) 40 | action: "action_ " (optional) 41 | banaction: "iptables-multiport" (optional) 42 | ``` 43 | 44 | There's a list of [service examples](services_examples.md) to help you. 45 | 46 | 47 | #### Testing 48 | This project comes with a VagrantFile, this is a fast and easy way to test changes to the role, fire it up with `vagrant up` 49 | 50 | See [vagrant docs](https://docs.vagrantup.com/v2/) for getting setup with vagrant 51 | 52 | 53 | #### License 54 | 55 | Licensed under the MIT License. See the LICENSE file for details. 56 | 57 | 58 | #### Feedback, bug-reports, requests, ... 59 | 60 | Are [welcome](https://github.com/ANXS/fail2ban/issues)! 61 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure('2') do |config| 5 | config.vm.define 'anxs' do |c| 6 | c.vm.box = 'ubuntu/trusty64' 7 | c.vm.network :private_network, ip: '192.168.88.8' 8 | c.vm.hostname = 'anxs.local' 9 | c.vm.provision 'ansible' do |ansible| 10 | ansible.playbook = 'test.yml' 11 | ansible.sudo = true 12 | ansible.inventory_path = 'vagrant-inventory' 13 | ansible.host_key_checking = false 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fail2ban_loglevel: 'INFO' 3 | fail2ban_logtarget: "/var/log/fail2ban.log" 4 | 5 | fail2ban_ignoreip: ["127.0.0.1/8"] 6 | fail2ban_bantime: "10m" 7 | fail2ban_maxretry: 3 8 | fail2ban_backend: "auto" 9 | fail2ban_destemail: "root@localhost" 10 | fail2ban_banaction: "iptables-multiport" 11 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "restart fail2ban" 3 | service: 4 | name: fail2ban 5 | state: restarted 6 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | # file: fail2ban/meta/main.yml 2 | 3 | galaxy_info: 4 | author: pjan vandaele 5 | company: ANXS 6 | description: Install and configure fail2ban 7 | min_ansible_version: 1.4 8 | license: MIT 9 | platforms: 10 | - name: Ubuntu 11 | versions: 12 | - all 13 | galaxy_tags: 14 | - system 15 | 16 | dependencies: [] 17 | -------------------------------------------------------------------------------- /services_examples.md: -------------------------------------------------------------------------------- 1 | ### ANXS - fail2ban: List of service examples 2 | 3 | ###### ssh/dropbear/... 4 | ```yaml 5 | - name: ssh 6 | enabled: "true" 7 | port: ssh 8 | filter: sshd 9 | logpath: /var/log/auth.log 10 | ``` 11 | 12 | ###### Generic filter for pam 13 | ```yaml 14 | fail2ban_services: 15 | - name: pam-generic 16 | enabled: "true" 17 | port: all 18 | filter: pam-generic 19 | logpath: /var/log/auth.log 20 | maxretry: 6 21 | banaction: iptables-allports 22 | ``` 23 | 24 | ###### xinetd-fail 25 | ```yaml 26 | fail2ban_services: 27 | - name: xinetd-fail 28 | enabled: "true" 29 | port: all 30 | filter: xinetd-fail 31 | logpath: /var/log/daemon.log 32 | maxretry: 2 33 | banaction: iptables-multiport-log 34 | ``` 35 | 36 | ###### ssh-ddos 37 | ```yaml 38 | fail2ban_services: 39 | - name: ssh-ddos 40 | enabled: "true" 41 | port: ssh 42 | filter: ssh-ddos 43 | logpath: /var/log/auth.log 44 | maxretry: 6 45 | ``` 46 | 47 | ###### apache 48 | ```yaml 49 | fail2ban_services: 50 | - name: apache 51 | enabled: "true" 52 | port: http,https 53 | filter: apache-auth 54 | logpath: /var/log/apache*/*error.log 55 | maxretry: 6 56 | ``` 57 | 58 | ###### apache-multiport 59 | ```yaml 60 | fail2ban_services: 61 | - name: apache-multiport 62 | enabled: "true" 63 | port: http,https 64 | filter: apache-auth 65 | logpath: /var/log/apache*/*error.log 66 | maxretry: 6 67 | banaction: 68 | ``` 69 | 70 | ###### apache-noscript 71 | ```yaml 72 | fail2ban_services: 73 | - name: apache-noscript 74 | enabled: "true" 75 | port: http,https 76 | filter: apache-noscript 77 | logpath: /var/log/apache*/*error.log 78 | maxretry: 6 79 | ``` 80 | 81 | ###### apache-overflows 82 | ```yaml 83 | fail2ban_services: 84 | - name: apache-overflows 85 | enabled: "true" 86 | port: http,https 87 | filter: apache-overflows 88 | logpath: /var/log/apache*/*error.log 89 | maxretry: 2 90 | ``` 91 | 92 | ###### vsftpd 93 | ```yaml 94 | fail2ban_services: 95 | - name: vsftpd 96 | enabled: "true" 97 | port: ftp,ftp-data,ftps,ftps-data 98 | filter: vsftpd 99 | logpath: /var/log/vsftpd.log 100 | maxretry: 6 101 | ``` 102 | 103 | ###### proftpd 104 | ```yaml 105 | fail2ban_services: 106 | - name: proftpd 107 | enabled: "true" 108 | port: ftp,ftp-data,ftps,ftps-data 109 | filter: proftpd 110 | logpath: /var/log/proftpd/proftpd.log 111 | maxretry: 6 112 | ``` 113 | 114 | ###### postfix 115 | ```yaml 116 | fail2ban_services: 117 | - name: postfix 118 | enabled: "true" 119 | port: smtp, ssmtp 120 | filter: postfix 121 | logpath: /var/log/mail.log 122 | maxretry: 6 123 | ``` 124 | 125 | ###### couriersmtp 126 | ```yaml 127 | fail2ban_services: 128 | - name: couriersmtp 129 | enabled: "true" 130 | port: smtp,ssmtp 131 | filter: couriersmtp 132 | logpath: /var/log/mail.log 133 | maxretry: 6 134 | ``` 135 | 136 | ###### courierauth 137 | ```yaml 138 | fail2ban_services: 139 | - name: courierauth 140 | enabled: "true" 141 | port: smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s 142 | filter: courierlogin 143 | logpath: /var/log/mail.log 144 | maxretry: 6 145 | ``` 146 | 147 | ###### sasl 148 | ```yaml 149 | fail2ban_services: 150 | - name: sasl 151 | enabled: "true" 152 | port: smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s 153 | filter: sasl 154 | logpath: /var/log/mail.log 155 | maxretry: 6 156 | ``` 157 | 158 | ###### dovecot 159 | ```yaml 160 | fail2ban_services: 161 | - name: dovecot 162 | enabled: "true" 163 | port: smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s 164 | filter: dovecot 165 | logpath: /var/log/mail.log 166 | maxretry: 6 167 | ``` 168 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "Make sure fail2ban is installed" 3 | apt: 4 | pkg: "fail2ban" 5 | state: "latest" 6 | 7 | - name: "Make sure the fail2ban configuration is up to date" 8 | template: 9 | src: "fail2ban.conf.j2" 10 | dest: "/etc/fail2ban/fail2ban.conf" 11 | owner: "root" 12 | group: "root" 13 | mode: "0644" 14 | notify: 15 | - "restart fail2ban" 16 | 17 | - name: "Generate fail2ban jail dot local" 18 | template: 19 | src: "jail.conf.j2" 20 | dest: "/etc/fail2ban/jail.local" 21 | owner: "root" 22 | group: "root" 23 | mode: "0644" 24 | notify: 25 | - "restart fail2ban" 26 | 27 | - name: "Make sure fail2ban is enabled" 28 | service: 29 | name: "fail2ban" 30 | enabled: true 31 | -------------------------------------------------------------------------------- /templates/fail2ban.conf.j2: -------------------------------------------------------------------------------- 1 | # Fail2Ban main configuration file 2 | # {{ansible_managed}} 3 | # Comments: use '#' for comment lines and ';' (following a space) for inline comments 4 | # 5 | # Changes: in most of the cases you should not modify this 6 | # file, but provide customizations in fail2ban.local file, e.g.: 7 | # 8 | # [DEFAULT] 9 | # loglevel = DEBUG 10 | # 11 | 12 | [DEFAULT] 13 | 14 | # Option: loglevel 15 | # Notes.: Set the log level output. 16 | # CRITICAL 17 | # ERROR 18 | # WARNING 19 | # NOTICE 20 | # INFO 21 | # DEBUG 22 | # Values: [ LEVEL ] Default: ERROR 23 | # 24 | loglevel = {{fail2ban_loglevel|upper}} 25 | 26 | # Option: logtarget 27 | # Notes.: Set the log target. This could be a file, SYSLOG, STDERR or STDOUT. 28 | # Only one log target can be specified. 29 | # If you change logtarget from the default value and you are 30 | # using logrotate -- also adjust or disable rotation in the 31 | # corresponding configuration file 32 | # (e.g. /etc/logrotate.d/fail2ban on Debian systems) 33 | # Values: [ STDOUT | STDERR | SYSLOG | SYSOUT | FILE ] Default: STDERR 34 | # 35 | logtarget = {{fail2ban_logtarget}} 36 | 37 | # Option: syslogsocket 38 | # Notes: Set the syslog socket file. Only used when logtarget is SYSLOG 39 | # auto uses platform.system() to determine predefined paths 40 | # Values: [ auto | FILE ] Default: auto 41 | syslogsocket = auto 42 | 43 | # Option: socket 44 | # Notes.: Set the socket file. This is used to communicate with the daemon. Do 45 | # not remove this file when Fail2ban runs. It will not be possible to 46 | # communicate with the server afterwards. 47 | # Values: [ FILE ] Default: /var/run/fail2ban/fail2ban.sock 48 | # 49 | socket = /var/run/fail2ban/fail2ban.sock 50 | 51 | # Option: pidfile 52 | # Notes.: Set the PID file. This is used to store the process ID of the 53 | # fail2ban server. 54 | # Values: [ FILE ] Default: /var/run/fail2ban/fail2ban.pid 55 | # 56 | pidfile = /var/run/fail2ban/fail2ban.pid 57 | 58 | # Options: dbfile 59 | # Notes.: Set the file for the fail2ban persistent data to be stored. 60 | # A value of ":memory:" means database is only stored in memory 61 | # and data is lost when fail2ban is stopped. 62 | # A value of "None" disables the database. 63 | # Values: [ None :memory: FILE ] Default: /var/lib/fail2ban/fail2ban.sqlite3 64 | dbfile = /var/lib/fail2ban/fail2ban.sqlite3 65 | 66 | # Options: dbpurgeage 67 | # Notes.: Sets age at which bans should be purged from the database 68 | # Values: [ SECONDS ] Default: 86400 (24hours) 69 | dbpurgeage = 1d 70 | 71 | # Options: dbmaxmatches 72 | # Notes.: Number of matches stored in database per ticket (resolvable via 73 | # tags / in actions) 74 | # Values: [ INT ] Default: 10 75 | dbmaxmatches = 10 76 | 77 | [Definition] 78 | 79 | 80 | [Thread] 81 | 82 | # Options: stacksize 83 | # Notes.: Specifies the stack size (in KiB) to be used for subsequently created threads, 84 | # and must be 0 or a positive integer value of at least 32. 85 | # Values: [ SIZE ] Default: 0 (use platform or configured default) 86 | #stacksize = 0 87 | -------------------------------------------------------------------------------- /templates/jail.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ansible_managed}} 2 | 3 | [DEFAULT] 4 | bantime = {{fail2ban_bantime}} 5 | ignoreip = {{fail2ban_ignoreip|join(" ")}} 6 | maxretry = {{fail2ban_maxretry}} 7 | backend = {{fail2ban_backend}} 8 | destemail = {{fail2ban_destemail}} 9 | fail2ban_banaction = {{fail2ban_banaction}} 10 | enabled = false 11 | -------------------------------------------------------------------------------- /test.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | vars_files: 3 | - 'defaults/main.yml' 4 | tasks: 5 | - include: 'tasks/main.yml' 6 | handlers: 7 | - include: 'handlers/main.yml' 8 | -------------------------------------------------------------------------------- /vagrant-inventory: -------------------------------------------------------------------------------- 1 | [anxs] 2 | anxs.local ansible_ssh_host=192.168.88.8 ansible_ssh_port=22 3 | --------------------------------------------------------------------------------