Installing Fail2ban with an Ansible Role on Ubuntu 18.04 (Bionic Beaver)
Preamble
The Ansible role in question comes from Ansible Galaxy. It's linked here below, where you can read about it more if needs be:
Here's my method for making use of the role, which is within the context of an Ansible project that already automates the other aspects of setting up a server. It's necessary to have a provisioning playbook already in place, so you can incorporate the role shown in this post into the main project.
1 -- Acquiring the Files
Starting from within the root directory of your own Ansible server "provisioning" project (most likely a version controlled project).
Clone the ansible-fail2ban
repo from GitHub into your project:
$ git clone https://github.com/Oefenweb/ansible-fail2ban.git roles/fail2ban
Note: Alternatively you can use
ansible-galaxy install --roles-path roles/ tersmitten.fail2ban
if you don't mind the directory name for the role beingtersmitten.fail2ban
Include the new role in your main playbook file's list of roles to be performed on the host(s).
$ vim playbook.yml
Such as in this generic bare bones example here:
---
- name: provision ubuntu 18.04 (bionic beaver) servers
hosts: all
gather_facts: yes
roles:
- base
- users
- ufw
- fail2ban
- ntp
Note: It does need to match the actual role directory name, so change this entry here to
tersmitten.fail2ban
if you instead used the Ansible galaxy install command earlier.
2 -- Editing the Default Ansible Variables
Several default values for many Fail2ban configuration directives are already set in the role's defaults
directory.
Edit them as normal with your preferred fail2ban configuration values.
$ vim roles/fail2ban/defaults/main.yml
These are the general contents including one or two additions, removals, and changes of my own:
# defaults file for fail2ban
---
fail2ban_loglevel: 'INFO'
fail2ban_logtarget: /var/log/fail2ban.log
fail2ban_syslog_target: /var/log/fail2ban.log
fail2ban_syslog_facility: 1
fail2ban_socket: /var/run/fail2ban/fail2ban.sock
fail2ban_pidfile: /var/run/fail2ban/fail2ban.pid
fail2ban_sendername: 'Fail2ban'
fail2ban_ignoreips:
- 127.0.0.1/8
fail2ban_bantime: 3600
fail2ban_maxretry: 5
fail2ban_findtime: 600
fail2ban_backend: auto
fail2ban_destemail: root@localhost
fail2ban_banaction: ufw.conf
fail2ban_mta: sendmail
fail2ban_protocol: tcp
fail2ban_chain: INPUT
fail2ban_action: '%(action_)s'
fail2ban_services:
- name: sshd
port: ssh
maxretry: 5
bantime: -1
These Ansible variables are applied onto the target host through two Jinja templates. Variables here are split into one of these two files (see the template files themselves for specifics). New variables you wish to incorporate have to be added to defaults/main.yml
and the relevant Jinja template file if not present.
Here's the reference for the Ansible variables on offer, used by this role.
You could also override them in the vars/main.yml
file too, if that seems more appealing, but do not define duplicate variables.
$ vim roles/fail2ban/vars/main.yml
This is the same common SSH daemon jail I added earlier, but in the alternative file:
# vars file for fail2ban
---
fail2ban_dependencies:
- fail2ban
fail2ban_services:
- name: sshd
port: ssh
maxretry: 5
bantime: -1
Remember not to duplicate variables between these two files!
So regardless of the file you choose, new jails must be included as part of the one fail2ban_services:
variable.
For example, adding a second Nginx jail:
fail2ban_services:
- name: sshd
port: ssh
maxretry: 5
bantime: -1
- name: nginx-http-auth
filter: nginx-http-auth
port: http,https
logpath: /var/log/nginx/access.log
The next section glosses over how the tasks of the role actually work.
3 -- Examining the Role's Tasks
Taking a glance at the tasks/main.yml
is worthwhile. It explains how the variables from the previous section are implemented, alongside the Jinja file templates, that are to be processed and copied across.
The first block of YAML is a task that creates/copies the local version of the main Fail2ban configuration file, onto the target.
- name: update configuration file - /etc/fail2ban/fail2ban.local
template:
src: etc/fail2ban/fail2ban.local.j2
dest: /etc/fail2ban/fail2ban.local
owner: root
group: root
mode: 0644
notify: restart fail2ban
tags:
- configuration
- fail2ban
- fail2ban-configuration
The second block of YAML is a task that creates/copies the local version of the Fail2ban jail configuration file, again onto the target.
- name: update configuration file - /etc/fail2ban/jail.local
template:
src: etc/fail2ban/jail.local.j2
dest: /etc/fail2ban/jail.local
owner: root
group: root
mode: 0644
notify: restart fail2ban
tags:
- configuration
- fail2ban
- fail2ban-configuration
The third task block only runs when the fail2ban_filterd_path
variable is set. Which assigns the path to the directory containing custom "filter" files, that you need copying across.
- name: copy filters
copy:
src: "{{ fail2ban_filterd_path }}"
dest: /etc/fail2ban/filter.d/
owner: root
group: root
mode: 0644
when: fail2ban_filterd_path is defined
notify: restart fail2ban
tags:
- configuration
- fail2ban
- fail2ban-filters
The next task block only runs when the fail2ban_actiond_path
variable is set. Which assigns the local path to the directory containing custom "actions" files, that you need copying across.
- name: copy actions
copy:
src: "{{ fail2ban_actiond_path }}"
dest: /etc/fail2ban/action.d/
owner: root
group: root
mode: 0644
when: fail2ban_actiond_path is defined
notify: restart fail2ban
tags:
- configuration
- fail2ban
- fail2ban-actions
And the final task displayed here runs when the fail2ban_actiond_jail
variable is set. Similarily this defines the local path to the directory containing custom "jail" configs.
- name: copy jails
copy:
src: "{{ fail2ban_jaild_path }}"
dest: /etc/fail2ban/jail.d/
owner: root
group: root
mode: 0644
when: fail2ban_jaild_path is defined
notify: restart fail2ban
tags:
- configuration
- fail2ban
- fail2ban-jails
Hopefully this all makes sense, explaining how the role is written and used.
4 -- Testing and Running the Playbook Role
After all of this is in place, test the new role by running your playbook.
This could be either as part of a Vagrant VM, Docker container, or on a live host.
From a live host's perspective, on a blank Ubuntu 18.04 Bionic server, and using the global hosts
file with all the hosts defined beforehand, un a syntax check on the playbook to ensure it's all legit.
$ ansible-playbook playbook.yml --syntax-check
No errors in terms of the written contents means you're good to actually run the playbook.
But wait, in order to examine how the role's tasks play out (yay puns), without actually implementing anything remotely, there's the --check
option.
$ ansible-playbook -l test-host -u root playbook.yml --check
Note: Some modules cannot properly complete their operations in "--check" mode so may fail (e.g. the user module when attempting to create encrypted system passwords for users).
This is optional but a convenient way of seeing the results before actually committing, so to speak.
Now we're certain everything's as it should be, here's the command to directly run the playbook, and in turn the Fail2ban installation role.
$ ansible-playbook -l test-host -u root playbook.yml
A bonus idea is to "tag" your roles in the main playbook using this form of syntax on line 10:
---
- name: provision ubuntu 18.04 (bionic beaver) droplets
hosts: all
gather_facts: yes
roles:
- fixes
- base
- users
- ufw
- {role: 'fail2ban', tags: 'fail2ban'}
- ntp
Which allows you to run only this role at playbook runtime, excluding the other listed roles.
So once tagged (in regards to the above), execute the playbook and specify the "fail2ban" tagging:
$ ansible-playbook -l test-host -u root playbook.yml --tags "fail2ban" --check
This is once again useful for selective testing purposes.
Note: From what I can tell there's no inbuilt function in Ansible to run select individual roles in a playbook, other than this
tags:
directive, unfortunately.
Check the two files in the remote server's /etc/fail2ban
to see the applied directives from our defaults/main.yml
file. This is the best way of confirming the changes we wanted are now in effect; Ansible does confirm and show changes during it's task execution though!
$ sudo less /etc/fail2ban/jail.local
$ sudo less /etc/fail2ban/fail2ban.local
Another brief post I may publish in the future, will go into detail on some further examples of jail configs, for various services.
Thanks!
More Information
- ServerWise -- Tutorial: A More Secure Ansible Playbook, Part 2
- Official Ansible Documentation -- Check Mode (“Dry Run”)
- Stack Overflow -- Ansible: Can I execute a role from the command line?
Easily deploy an SSD cloud server on Digital Ocean in 55 seconds. Sign up using my link and receive $10.00 in free credit: https://www.digitalocean.com/?refcode=e91058dbfc7b
Congratulations @countelmsley! You have completed some achievement on Steemit and have been rewarded with new badge(s) :
You published your First Post
You got a First Vote
Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word
STOP
Congratulations @countelmsley! You received a personal award!
Click here to view your Board
Congratulations @countelmsley! You received a personal award!
You can view your badges on your Steem Board and compare to others on the Steem Ranking
Vote for @Steemitboard as a witness to get one more award and increased upvotes!