davideaves.com

Live in a world of your own, but always welcome visitors.

View on GitHub
27 November 2017

Preventing brute force login attempts by merging geoiplookup and hosts_access

by deaves

To me networking and UNIX run hand-in-hand; as I have been getting into Ansible to do network automation I am also using it to automate and enforce consistency between all of my other hosts. The following is a simple playbook to configure Debian based hosts to perform a geoiplookup against all incoming hosts to prevent brute force login attempts using host_access. I have to admit the original script and idea are not mine; they originated from the following blog post: Limit your SSH logins using GeoIP. As more and more systems are migrated into cloud environments automating and enforcing security controls like this one are of critical importance.

geowrapper.yaml: a /usr/local/bin/ansible-playbook script, ASCII text executable

#!/usr/local/bin/ansible-playbook
## Configure Debian OS family to geoiplookup against all incoming hosts.
## 2017 (v.01) - Playbook from www.davideaves.com
---
- name: GEO Wrapper
  hosts: all
  become: yes
  gather_facts: yes
  tags: host_access

  vars:
    geocountries: "US"
    geofilter: "/opt/geowrapper.sh"

  tasks:
  - name: "Fail if OS family not Debian"
    fail:
      msg: "Distribution not supported"
    when: ansible_os_family != "Debian"

  - name: "Fetch geoip packages"
    apt:
      name:
        - geoip-bin
        - geoip-database
      state: latest
      update_cache: yes
    register: geoip
    when: ansible_os_family == "Debian"

  - name: "Wrapper script "
    copy:
      content: |
        #!/bin/bash
        # Ansible Managed: GeoIP aclexec script for Linux TCP wrappers.
        ## Source: http://www.axllent.org/docs/view/ssh-geoip

        # UPPERCASE space-separated country codes to ACCEPT
        ALLOW_COUNTRIES=""

        if [ $# -ne 1 ]; then
          echo "Usage:  `basename $0` ip" 1>&2
          exit 0 # return true in case of config issue
        fi

        COUNTRY=`/usr/bin/geoiplookup $1 | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`

        [[ $COUNTRY = "IP Address not found" || $ALLOW_COUNTRIES =~ $COUNTRY ]] && RESPONSE="ALLOW" || RESPONSE="DENY"

        if [ $RESPONSE = "ALLOW" ]
        then
          exit 0
        else
          logger "$RESPONSE connection from $1 ($COUNTRY)"
          exit 1
        fi
      dest: ""
      mode: "0755"
      owner: root
      group: root
    ignore_errors: yes
    register: geowrapper
    when: geoip|success

  - name: "Mappings in /etc/hosts.allow"
    blockinfile:
      path: /etc/hosts.allow
      state: present
      content: |
        ALL: 10.0.0.0/8
        ALL: 172.16.0.0/12
        ALL: 192.168.0.0/16
        ALL: ALL: aclexec  %a
    when: geowrapper|success

  - name: "Mappings in /etc/hosts.deny"
    blockinfile:
      path: /etc/hosts.deny
      state: present
      content: "ALL: ALL"
    when: geowrapper|success
tags: aclexec - ansible - geoip - geoiplookup - hosts.allow - linux acl - tcp wrappers