From: David Galloway Date: Fri, 10 Feb 2017 21:08:44 +0000 (-0500) Subject: public_facing: Add fail2ban support X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=711c4c7486df684cb4859135977ab14b21ceb7ce;p=ceph-cm-ansible.git public_facing: Add fail2ban support Signed-off-by: David Galloway --- diff --git a/roles/public_facing/README.rst b/roles/public_facing/README.rst index d1bb6d7..5f24bd4 100644 --- a/roles/public_facing/README.rst +++ b/roles/public_facing/README.rst @@ -19,10 +19,36 @@ Variables 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. @@ -34,14 +60,26 @@ 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: " .*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 diff --git a/roles/public_facing/defaults/main.yml b/roles/public_facing/defaults/main.yml index 2f405bd..0c7567e 100644 --- a/roles/public_facing/defaults/main.yml +++ b/roles/public_facing/defaults/main.yml @@ -7,3 +7,31 @@ use_ufw: false # 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 }}" diff --git a/roles/public_facing/handlers/main.yml b/roles/public_facing/handlers/main.yml new file mode 100644 index 0000000..99bcd68 --- /dev/null +++ b/roles/public_facing/handlers/main.yml @@ -0,0 +1,12 @@ +--- +# Restart fail2ban +- name: restart fail2ban + service: + name: fail2ban + state: restarted + +# Reload fail2ban +- name: reload fail2ban + service: + name: fail2ban + state: reloaded diff --git a/roles/public_facing/tasks/fail2ban.yml b/roles/public_facing/tasks/fail2ban.yml new file mode 100644 index 0000000..362fe58 --- /dev/null +++ b/roles/public_facing/tasks/fail2ban.yml @@ -0,0 +1,77 @@ +--- +- 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 diff --git a/roles/public_facing/tasks/main.yml b/roles/public_facing/tasks/main.yml index 274c454..7be38db 100644 --- a/roles/public_facing/tasks/main.yml +++ b/roles/public_facing/tasks/main.yml @@ -8,6 +8,11 @@ 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' diff --git a/roles/public_facing/templates/f2b.filter.j2 b/roles/public_facing/templates/f2b.filter.j2 new file mode 100644 index 0000000..4cc8df0 --- /dev/null +++ b/roles/public_facing/templates/f2b.filter.j2 @@ -0,0 +1,5 @@ +# +# {{ ansible_managed }} +# +[Definition] +failregex = {{ item.value.failregex }} diff --git a/roles/public_facing/templates/f2b.jail.local.j2 b/roles/public_facing/templates/f2b.jail.local.j2 new file mode 100644 index 0000000..65d840c --- /dev/null +++ b/roles/public_facing/templates/f2b.jail.local.j2 @@ -0,0 +1,13 @@ +# +# {{ 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 %} diff --git a/roles/public_facing/templates/f2b.service.j2 b/roles/public_facing/templates/f2b.service.j2 new file mode 100644 index 0000000..9d176d2 --- /dev/null +++ b/roles/public_facing/templates/f2b.service.j2 @@ -0,0 +1,20 @@ +# +# {{ 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 %} diff --git a/roles/public_facing/templates/f2b_ufw.conf.j2 b/roles/public_facing/templates/f2b_ufw.conf.j2 new file mode 100644 index 0000000..140a02a --- /dev/null +++ b/roles/public_facing/templates/f2b_ufw.conf.j2 @@ -0,0 +1,11 @@ +# +# {{ ansible_managed }} +# +# Fail2Ban action configuration file for ufw + +[Definition] +actionstart = +actionstop = +actioncheck = +actionban = ufw insert 1 deny from to any port +actionunban = ufw delete deny from to any port