diff --git a/generator/app/templates/provisioning/group_vars/webservers b/generator/app/templates/provisioning/group_vars/webservers index c47f2df..f3e3199 100644 --- a/generator/app/templates/provisioning/group_vars/webservers +++ b/generator/app/templates/provisioning/group_vars/webservers @@ -18,3 +18,9 @@ apache_settings: # max_requests_per_child: mail: # postmaster: sysadmin@example.com +fail2ban: + # whitelist: + # - 127.0.0.0/8 + # ban_time: 600 + # notification_email: root@localhost + # notify_on_ban: 0 diff --git a/provisioning/provision.yml b/provisioning/provision.yml index 8677385..8be6fb7 100644 --- a/provisioning/provision.yml +++ b/provisioning/provision.yml @@ -3,5 +3,6 @@ gather_facts: yes roles: - common + - firewall - wordpress - varnish diff --git a/provisioning/roles/firewall/files/default/iptables-persistent.conf b/provisioning/roles/firewall/files/default/iptables-persistent.conf new file mode 100644 index 0000000..58fd4ec --- /dev/null +++ b/provisioning/roles/firewall/files/default/iptables-persistent.conf @@ -0,0 +1,15 @@ +# A basic config file for the /etc/init.d/iptable-persistent script +# See: https://github.com/zertrin/iptables-persistent + +# Should new manually added rules from command line be saved on reboot? Assign to a value different that 0 if you want this enabled. +SAVE_NEW_RULES=0 + +# Modules to load: +#modules="ip_conntrack_ftp" #example for ftp conntracking +modules="" + +# Enable Routing? Assign to a value different that 0 if you want this enabled. +ENABLE_ROUTING=0 + +# Enable IPv6? Assign to a value different that 0 if you want this enabled. +IPV6=0 diff --git a/provisioning/roles/firewall/files/fail2ban/filter.d/apache-wordpress.local b/provisioning/roles/firewall/files/fail2ban/filter.d/apache-wordpress.local new file mode 100644 index 0000000..7370aa9 --- /dev/null +++ b/provisioning/roles/firewall/files/fail2ban/filter.d/apache-wordpress.local @@ -0,0 +1,32 @@ +# Fail2Ban configuration file +# +# Author: Evan Kaufman +# +# $Revision$ +# + +[INCLUDES] + +# Read common prefixes. If any customizations available -- read them from +# common.local +before = apache-common.conf + +[Definition] + +# Option: failregex +# Notes.: regex to match certain Wordpress and PHP vulns, borrowed from: +# * http://www.fail2ban.org/wiki/index.php/Apache +# * http://blog.somsip.com/2012/02/using-fail2ban-to-protect-wordpress/ +# Values: TEXT +# +failregex = ^%(_apache_error_client)s PHP Notice:.*(Undefined variable: HTTP_.*_VARS in|Use of undefined constant include_path).*$ + ^%(_apache_error_client)s PHP Deprecated:.*(Function set_magic_quotes_runtime\(\) is deprecated in|Assigning the return value of new by reference is deprecated in).*$ + ^%(_apache_error_client)s (File does not exist|script ').*(phpMyAdmin|phpmyadmin|dbadmin|mysql|myadmin|w00t|muieblackcat|mysqladmin).*$ + +ignoreregex = + +# Option: ignoreregex +# Notes.: regex to ignore. If this regex matches, the line is ignored. +# Values: TEXT +# +ignoreregex = diff --git a/provisioning/roles/firewall/files/init.d/iptables-persistent b/provisioning/roles/firewall/files/init.d/iptables-persistent new file mode 100644 index 0000000..0cc5bcb --- /dev/null +++ b/provisioning/roles/firewall/files/init.d/iptables-persistent @@ -0,0 +1,164 @@ +#!/bin/sh +# See: https://github.com/zertrin/iptables-persistent +### BEGIN INIT INFO +# Provides: iptables +# Required-Start: mountkernfs $local_fs +# Required-Stop: $local_fs +# Default-Start: S +# Default-Stop: +# Short-Description: Set up iptables rules +### END INIT INFO + +PATH="/sbin:/bin:/usr/sbin:/usr/bin" + +# Include config file for iptables-persistent +. /etc/default/iptables-persistent.conf + +case "$1" in +start) + if [ -e /var/run/iptables ]; then + echo "iptables is already started!" + exit 1 + else + touch /var/run/iptables + fi + + # if fail2ban is already running, stop it the time needed to load the new rules + if [ -x /etc/init.d/fail2ban ]; then + /etc/init.d/fail2ban stop + fi + + if [ $ENABLE_ROUTING -ne 0 ]; then + # Enable Routing + echo 1 > /proc/sys/net/ipv4/ip_forward + if [ $IPV6 -ne 0 ]; then + echo 1 >/proc/sys/net/ipv6/conf/all/forwarding + fi + fi + + if [ $MODULES ]; then + # Load Modules + modprobe -a $MODULES + fi + + # Load saved rules + if [ -f /etc/iptables/rules ]; then + iptables-restore /etc/iptables/rules + + if [ $IPV6 -ne 0 ]; then + # Backup old rules + cp /etc/iptables/ipv6_rules /etc/iptables/ipv6_rules.bak + # Save new rules + ip6tables-save >/etc/iptables/ipv6_rules + fi + fi + + # stop fail2ban before flushing iptables chains + if [ -x /etc/init.d/fail2ban ]; then + /etc/init.d/fail2ban stop + fi + + # Restore Default Policies + iptables -P INPUT ACCEPT + iptables -P FORWARD ACCEPT + iptables -P OUTPUT ACCEPT + + # Flush rules on default tables + iptables -F + iptables -t nat -F + iptables -t mangle -F + + if [ $IPV6 -ne 0 ]; then + # Restore Default Policies + ip6tables -P INPUT ACCEPT + ip6tables -P FORWARD ACCEPT + ip6tables -P OUTPUT ACCEPT + + # Flush rules on default tables + ip6tables -F + ip6tables -t mangle -F + fi + + if [ $MODULES ]; then + # Unload previously loaded modules + modprobe -r $MODULES + fi + + # Disable Routing if enabled + if [ $ENABLE_ROUTING -ne 0 ]; then + # Disable Routing + echo 0 > /proc/sys/net/ipv4/ip_forward + if [ $IPV6 -ne 0 ]; then + echo 0 >/proc/sys/net/ipv6/conf/all/forwarding + fi + fi + + # start of fail2ban + if [ -x /etc/init.d/fail2ban ]; then + /etc/init.d/fail2ban start + fi + ;; + +restart|force-reload) + $0 stop + $0 start + ;; + +status) + echo "Filter Rules:" + echo "--------------" + iptables -L -v + echo "" + echo "NAT Rules:" + echo "-------------" + iptables -t nat -L -v + echo "" + echo "Mangle Rules:" + echo "----------------" + iptables -t mangle -L -v + + if [ $IPV6 -ne 0 ]; then + echo "**********" + echo "** IPV6 **" + echo "**********" + echo "Filter Rules:" + echo "--------------" + ip6tables -L -v + echo "" + echo "Mangle Rules:" + echo "----------------" + ip6tables -t mangle -L -v + fi + ;; + +*) + echo "Usage: $0 {start|stop|force-stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/provisioning/roles/firewall/files/iptables/ipv6_rules b/provisioning/roles/firewall/files/iptables/ipv6_rules new file mode 100644 index 0000000..f8d3c3c --- /dev/null +++ b/provisioning/roles/firewall/files/iptables/ipv6_rules @@ -0,0 +1,51 @@ +*filter +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] + +# allow all loopback traffic +-A INPUT -i lo -j ACCEPT + +# allow all ICMP traffic +-A INPUT -p icmpv6 -j ACCEPT + +# Drop any tcp packet that does not start a connection with a syn flag. +-A INPUT -p tcp ! --syn -m state --state NEW -j DROP +# packets belonging to an established connection or related to one can pass +-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +# packets that are out-of-sequence are silently dropped +-A INPUT -m state --state INVALID -j DROP + +# Allow incoming FTP +#-A INPUT -i eth+ -p tcp --dport 21 -j ACCEPT + +# Allow incoming SSH +-A INPUT -i eth+ -p tcp -m tcp --dport 22 -j ACCEPT + +# Allow incoming HTTP +-A INPUT -i eth+ -p tcp -m tcp --dport 80 -j ACCEPT + +# Allow incoming HTTPS +-A INPUT -i eth+ -p tcp -m tcp --dport 443 -j ACCEPT + +# Allow DNS +#-A OUTPUT -o eth+ -p tcp --dport 53 -j ACCEPT +#-A OUTPUT -o eth+ -p udp --dport 53 -j ACCEPT +#-A INPUT -i eth+ -p tcp --sport 53 -j ACCEPT +#-A INPUT -i eth+ -p udp --sport 53 -j ACCEPT + +# Log dropped packets +-N LOGGING +-A INPUT -j LOGGING +-A LOGGING -p tcp -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "iptables: [INPUT6 ][denied TCP] " --log-level 7 +-A LOGGING -p udp -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "iptables: [INPUT6 ][denied UDP] " --log-level 7 +-A LOGGING -p icmp -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "iptables: [INPUT6 ][denied ICMP] " --log-level 7 +-A INPUT -j REJECT + +# allow outgoing traffic, explicitly (despite chain policy) +-A OUTPUT -j ACCEPT + +# disallow forwarded traffic, explicitly (despite chain policy) +-A FORWARD -j REJECT + +COMMIT diff --git a/provisioning/roles/firewall/files/iptables/rules b/provisioning/roles/firewall/files/iptables/rules new file mode 100644 index 0000000..969446a --- /dev/null +++ b/provisioning/roles/firewall/files/iptables/rules @@ -0,0 +1,76 @@ +*nat +:PREROUTING ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +COMMIT + +*filter +# Set default chain policies +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] + +# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0 +-A INPUT -i lo -j ACCEPT +-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT + +# Drop any tcp packet that does not start a connection with a syn flag. +-A INPUT -p tcp ! --syn -m state --state NEW -j DROP + +# Accepts all established inbound connections +-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + +# Drop any invalid packet that could not be identified. +-A INPUT -m state --state INVALID -j DROP + +# Blacklist (examples) +#-A INPUT -i eth+ -s 198.51.100.1 -p tcp --dport 22 -j DROP # Example IP from RFC 5737 +#-A INPUT -i eth+ -s 203.0.113.34 -j DROP # Example IP from RFC 5737 + +# Allow incoming FTP +#-A INPUT -i eth+ -p tcp --dport 21 -j ACCEPT + +# Allow incoming SSH +-A INPUT -i eth+ -p tcp --dport 22 -j ACCEPT + +# Allow incoming HTTP +-A INPUT -i eth+ -p tcp --dport 80 -j ACCEPT + +# Allow incoming HTTPS +-A INPUT -i eth+ -p tcp --dport 443 -j ACCEPT + +# Allow ping from inside to outside +-A OUTPUT -o eth+ -p icmp --icmp-type echo-request -j ACCEPT +-A INPUT -i eth+ -p icmp --icmp-type echo-reply -m limit --limit 2/s -j ACCEPT + +# Allow ping from outside to inside +-A INPUT -i eth+ -p icmp --icmp-type echo-request -m limit --limit 2/s -j ACCEPT +-A OUTPUT -o eth+ -p icmp --icmp-type echo-reply -j ACCEPT + +# Allow NTP +#-A INPUT -i eth+ -p udp --dport 123 -j ACCEPT +#-A OUTPUT -o eth+ -p udp --sport 123 -j ACCEPT + +# Allow DNS +#-A OUTPUT -o eth+ -p tcp --dport 53 -j ACCEPT +#-A OUTPUT -o eth+ -p udp --dport 53 -j ACCEPT +#-A INPUT -i eth+ -p tcp --sport 53 -j ACCEPT +#-A INPUT -i eth+ -p udp --sport 53 -j ACCEPT + +# Log dropped packets +-N LOGGING +-A INPUT -j LOGGING +-A LOGGING -p tcp -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "iptables: [denied TCP] " --log-level 7 +-A LOGGING -p udp -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "iptables: [denied UDP] " --log-level 7 +-A LOGGING -p icmp -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "iptables: [denied ICMP] " --log-level 7 + +# Reject all other inbound - default deny unless explicitly allowed policy: +-A INPUT -j REJECT + +# Allow all other outbound traffic +-A OUTPUT -j ACCEPT + +# Reject forwarded traffic, explicitely (despite chain policy) +-A FORWARD -j REJECT + +COMMIT diff --git a/provisioning/roles/firewall/handlers/main.yml b/provisioning/roles/firewall/handlers/main.yml new file mode 100644 index 0000000..4d49f43 --- /dev/null +++ b/provisioning/roles/firewall/handlers/main.yml @@ -0,0 +1,4 @@ +--- +- name: restart iptables + command: /etc/init.d/iptables-persistent restart + sudo: true diff --git a/provisioning/roles/firewall/tasks/main.yml b/provisioning/roles/firewall/tasks/main.yml new file mode 100644 index 0000000..534848f --- /dev/null +++ b/provisioning/roles/firewall/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Install fail2ban + apt: pkg=fail2ban update_cache=yes + sudo: yes + +- name: Create iptables config directory + file: path=/etc/iptables state=directory + sudo: yes + +- name: Install fail2ban + iptables-persistent configs + copy: src=${item} dest=/etc/${item} mode=0644 + with_items: + - fail2ban/filter.d/apache-wordpress.local + - default/iptables-persistent.conf + - iptables/rules + - iptables/ipv6_rules + sudo: true + +- name: Configure fail2ban jail + template: src=fail2ban/jail.local dest=/etc/fail2ban/jail.local mode=0644 + sudo: true + +- name: Install iptables-persistent init.d script + copy: src=init.d/iptables-persistent dest=/etc/init.d/iptables-persistent mode=0755 + sudo: true + +- name: Register iptables-persistent init.d script + command: update-rc.d iptables-persistent defaults + sudo: true + notify: + - restart iptables diff --git a/provisioning/roles/firewall/templates/fail2ban/jail.local b/provisioning/roles/firewall/templates/fail2ban/jail.local new file mode 100644 index 0000000..4705ac3 --- /dev/null +++ b/provisioning/roles/firewall/templates/fail2ban/jail.local @@ -0,0 +1,76 @@ +## Overrides of distribution-provided fail2ban jail.conf + +# Global definition of options, can be overridden in each jail afterwards. +[DEFAULT] + +{% if fail2ban is defined and fail2ban.whitelist is defined %} +# Can be space separated IP addresses, CIDR masks or DNS hosts +ignoreip = 127.0.0.0/8 {{ fail2ban.whitelist | join(' ') }} + +{% endif %} +{% if fail2ban is defined and fail2ban.ban_time is defined %} +# Global default ban time (in seconds) +bantime = {{fail2ban.ban_time}} + +{% endif %} +{% if fail2ban is defined and fail2ban.notification_email is defined %} +# Destination email for interpolations in jail.{conf,local} +destemail = {{fail2ban.notification_email}} + +{% endif %} +# Default banning action +banaction = iptables-multiport + +# Default action (e.g. action_ for ban only, action_mw for ban + email, action_mwl for ban + email w relevant log entries) +{% if fail2ban is defined and fail2ban.notify_on_ban is defined and fail2ban.notify_on_ban %} +action = %(action_mwl)s +{% else %} +action = %(action_)s +{% endif %} + +# Ignore all hostnames (rather than ips) in log files and optionally warn administrator that hostnames are being logged +# yes (default behavior) +# warn (uses but warns upon each dns lookup) +# no (no DNS lookup, no warnings, INFO-LEVEL log messages when rDNS was necessary and entry was ignored because of that) +use_dns = no + + +[ssh] + +enabled = true +port = ssh +filter = sshd +logpath = /var/log/auth.log +maxretry = 6 + +[ssh-ddos] + +enabled = true +port = ssh +filter = sshd-ddos +logpath = /var/log/auth.log +maxretry = 6 + +[apache] + +enabled = true +port = http,https +filter = apache-auth +logpath = /var/log/apache*/*error.log +maxretry = 6 + +[apache-overflows] + +enabled = true +port = http,https +filter = apache-overflows +logpath = /var/log/apache*/*error.log +maxretry = 2 + +[apache-wordpress] + +enabled = true +port = http,https +filter = apache-wordpress +logpath = /var/log/apache*/*error.log +maxretry = 3