Installing Fail2ban with an Ansible Role on Ubuntu 18.04 (Bionic Beaver)

in linux •  7 years ago  (edited)

Fail2ban Logo with Ansible Logo

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:

https://galaxy.ansible.com/tersmitten/fail2ban/

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 being tersmitten.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

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

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

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

Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Congratulations @countelmsley! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 1 year!

Click here to view your Board

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @countelmsley! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

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!