Defaults
--------
-Override these in your ansible inventory ``host_vars`` file.
+Defined in ``roles/public_facing/defaults/main.yml`` Override these in the ansible inventory ``host_vars`` file.
``use_ufw: false`` specifies whether an Ubuntu host should use UFW_
+``f2b_ignoreip: "127.0.0.1"``
+``f2b_bantime: "43200"``
+``f2b_findtime: "900"``
+``f2b_maxretry: 5``
+
+``use_fail2ban: true`` specifies whether a host should use fail2ban_
+
+``f2b_services: {}`` is a dictionary listing services fail2ban should monitor. See example below::
+
+ f2b_services:
+ sshd:
+ enabled: "true"
+ port: "22"
+ maxretry: 3
+ findtime: "3600" # 1hr
+ filter: "sshd"
+ logpath: "{{ sshd_logpath }}"
+ sshd-ddos:
+ enabled: "true"
+ port: "22"
+ maxretry: 3
+ filter: "sshd-ddos"
+ logpath: "{{ sshd_logpath }}"
+
+ # Note: sshd_logpath gets defined automatically in roles/public_facing/tasks/fail2ban.yml
+
host_vars
---------
If required, define these in your ansible inventory ``host_vars`` file.
- "80"
- "443"
+``f2b_filters: {}`` is a dictionary of additional filters fail2ban should use. For example, our status portal running Cachet has an additional fail2ban service monitoring repeated login attempts to the admin portal. See filter example::
+
+ f2b_filters:
+ apache-cachet:
+ failregex: "<HOST> .*GET /auth/login.*$"
+
Common Tasks
++++++++++++
+These are tasks that are applicable to all our public-facing hosts.
+
UFW
---
At the time of this writing, we only have one public-facing host that doesn't run Ubuntu -- the nameserver. Its firewall is managed in the ``nameserver`` role.
-Despite having network port ACLs defined for each host in our cloud provider's interface, enabling a firewall local to the system will allow us to block abusive IPs using fail2ban_.
+Despite having network port ACLs defined for each host in our cloud provider's interface, enabling a firewall local to the system will allow us to block abusive IPs using fail2ban.
+
+fail2ban
+--------
+If ``use_fail2ban`` is set to ``true`` this role will install, configure, and enable fail2ban.
.. _UFW: https://wiki.ubuntu.com/UncomplicatedFirewall
# Default to allow SSH traffic.
ufw_allowed_ports:
- "22"
+
+# Use fail2ban by default
+use_fail2ban: true
+
+# Defaults for global fail2ban overrides in /etc/fail2ban/jail.local
+# Override in ansible inventory host_vars, group_vars, or some can be
+# overridden by service files in the f2b_services dict. See README.
+f2b_ignoreip: "127.0.0.1"
+f2b_bantime: "43200" # 12 hours
+f2b_findtime: "900" # 15 minutes
+f2b_maxretry: 5
+
+# Default fail2ban services to block. This can be overridden in ansible
+# inventory group_vars or host_vars.
+f2b_services:
+ sshd:
+ enabled: "true"
+ port: "22"
+ maxretry: 3
+ findtime: "3600" # 1hr
+ filter: "sshd"
+ logpath: "{{ sshd_logpath }}"
+ sshd-ddos:
+ enabled: "true"
+ port: "22"
+ maxretry: 3
+ filter: "sshd-ddos"
+ logpath: "{{ sshd_logpath }}"
--- /dev/null
+---
+# Restart fail2ban
+- name: restart fail2ban
+ service:
+ name: fail2ban
+ state: restarted
+
+# Reload fail2ban
+- name: reload fail2ban
+ service:
+ name: fail2ban
+ state: reloaded
--- /dev/null
+---
+- name: Install or update fail2ban
+ package:
+ name: fail2ban
+ state: latest
+
+- name: Check if firewalld is running
+ shell: firewall-cmd --state
+ register: firewalld_status
+ # Don't fail if command not found
+ failed_when: false
+
+- name: Set f2b_banaction if using firewalld
+ set_fact:
+ f2b_banaction: "firewallcmd-ipset"
+ when: firewalld_status.stdout == "running"
+
+- name: Check if UFW is running
+ shell: ufw status | grep Status | cut -d ' ' -f2
+ register: ufw_status
+ # Don't fail if command not found
+ failed_when: false
+
+- name: Set f2b_banaction if using UFW
+ set_fact:
+ f2b_banaction: "ufw"
+ when: ufw_status.stdout == "active"
+
+- name: Write /etc/fail2ban/action.d/ufw.conf if it's missing
+ template:
+ src: f2b_ufw.conf.j2
+ dest: /etc/fail2ban/action.d/ufw.conf
+ when: use_ufw == true
+
+# Any parameters defined in this file overwrite the package-provided jail.conf
+- name: Write global fail2ban defaults
+ template:
+ src: templates/f2b.jail.local.j2
+ dest: /etc/fail2ban/jail.local
+ notify: restart fail2ban
+
+# sshd_logpath is used in the f2b_services dictionary. fail2ban doesn't know
+# where ssh logs are for services other than sshd so sshd-ddos, for example
+# needs to be told where to look. For other services (e.g., nginx), the logpath
+# can be set directly in the dict.
+- name: Set sshd_logpath for CentOS/RHEL
+ set_fact:
+ sshd_logpath: "/var/log/messages"
+ when: ansible_os_family == "RedHat"
+
+- name: Set sshd_logpath for Ubuntu
+ set_fact:
+ sshd_logpath: "/var/log/auth.log"
+ when: ansible_os_family == "Debian"
+
+# This makes sure there are no old or malformed service conf files.
+# We'll rewrite them in the next task.
+- name: Clean up local service conf files
+ shell: rm -f /etc/fail2ban/jail.d/*.local
+
+- name: Write fail2ban service conf files
+ template:
+ src: templates/f2b.service.j2
+ dest: "/etc/fail2ban/jail.d/{{ item.key }}.local"
+ with_dict: "{{ f2b_services }}"
+ notify: reload fail2ban
+
+- name: Clean up local filter conf files
+ shell: rm -f /etc/fail2ban/filter.d/*.local
+
+- name: Write fail2ban filter conf files
+ template:
+ src: templates/f2b.filter.j2
+ dest: "/etc/fail2ban/filter.d/{{ item.key }}.local"
+ with_dict: "{{ f2b_filters }}"
+ when: f2b_filters is defined
+ notify: reload fail2ban
tags:
- always
+- include: fail2ban.yml
+ tags:
+ - always
+ when: use_fail2ban == true
+
## Individual host tasks
# local_action in the task after this causes 'ansible_host' to change to 'localhost'
--- /dev/null
+#
+# {{ ansible_managed }}
+#
+[Definition]
+failregex = {{ item.value.failregex }}
--- /dev/null
+#
+# {{ ansible_managed }}
+#
+
+# These are global overrides of jail.conf
+[DEFAULT]
+ignoreip = {{ f2b_ignoreip }}
+bantime = {{ f2b_bantime }}
+findtime = {{ f2b_findtime }}
+maxretry = {{ f2b_maxretry }}
+{% if f2b_banaction is defined %}
+banaction = {{ f2b_banaction }}
+{% endif %}
--- /dev/null
+#
+# {{ ansible_managed }}
+#
+[{{ item.key }}]
+enabled = {{ item.value.enabled }}
+{% if item.value.maxretry is defined %}
+maxretry = {{ item.value.maxretry }}
+{% endif %}
+{% if item.value.port is defined %}
+port = {{ item.value.port }}
+{% endif %}
+{% if item.value.findtime is defined %}
+findtime = {{ item.value.findtime }}
+{% endif %}
+{% if item.value.logpath is defined %}
+logpath = {{ item.value.logpath }}
+{% endif %}
+{% if item.value.filter is defined %}
+filter = {{ item.value.filter }}
+{% endif %}
--- /dev/null
+#
+# {{ ansible_managed }}
+#
+# Fail2Ban action configuration file for ufw
+
+[Definition]
+actionstart =
+actionstop =
+actioncheck =
+actionban = ufw insert 1 deny from <ip> to any port <port>
+actionunban = ufw delete deny from <ip> to any port <port>