From 39b526a6a4631841afdea652cd84d5983ebc3e01 Mon Sep 17 00:00:00 2001 From: Ryan Cavicchioni Date: Tue, 27 Aug 2019 05:35:14 +0000 Subject: [PATCH] Add SSH brute force and ICMP flood limitting, other improvements --- roles/firewall/defaults/main.yaml | 5 ++- roles/firewall/templates/ip6tables.j2 | 55 ++++++++++++++------------- roles/firewall/templates/iptables.j2 | 51 +++++++++++++------------ 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/roles/firewall/defaults/main.yaml b/roles/firewall/defaults/main.yaml index 93fabc0..d7a545e 100644 --- a/roles/firewall/defaults/main.yaml +++ b/roles/firewall/defaults/main.yaml @@ -35,8 +35,9 @@ firewall_allowed_udp_ports: {} firewall_log_limit: 3/min firewall_log_limit_burst: 10 -firewall_limit_seconds: 60 -firewall_limit_hitcount: 10 +firewall_limit_ssh: true +firewall_limit_ssh_seconds: 60 +firewall_limit_ssh_hitcount: 10 firewall_bogon_interface: "{{ ansible_default_ipv4.interface }}" diff --git a/roles/firewall/templates/ip6tables.j2 b/roles/firewall/templates/ip6tables.j2 index 8e2608c..e2d09fc 100644 --- a/roles/firewall/templates/ip6tables.j2 +++ b/roles/firewall/templates/ip6tables.j2 @@ -3,42 +3,43 @@ :FORWARD {{ firewall_iptables_forward_policy_v6 }} :OUTPUT {{ firewall_iptables_output_policy_v6 }} -:LIMIT - - -:LOG_LIMIT - -:LOG_ACCEPT - -:LOG_DROP - - +-N LOG_ACCEPT -A LOG_ACCEPT -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables ACCEPT] " --log-level info -A LOG_ACCEPT -j ACCEPT +-N LOG_DROP -A LOG_DROP -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables DROP] " --log-level info --A LOG_DROP -j DROP +-A LOG_DROP -p tcp -m tcp -m comment --comment "reject tcp" -j REJECT --reject-with tcp-reset +-A LOG_DROP -p udp -m udp -m comment --comment "drop udp" -j DROP +-A LOG_DROP -m comment --comment "reject all" -j REJECT --reject-with icmp6-adm-prohibited --A LOG_LIMIT -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables LIMIT] " --log-level info --A LOG_LIMIT -j DROP - --A LIMIT -m state --state NEW -m recent --set --A LIMIT -m state --state NEW -m recent --update --seconds {{ firewall_limit_seconds }} --hitcount {{ firewall_limit_hitcount }} -j LOG_LIMIT --A LIMIT -j ACCEPT +{% if firewall_limit_ssh %} +-N LIMIT_SSH +-A LIMIT_SSH -m recent --set --name SSH --rsource +-A LIMIT_SSH -m recent --update --seconds {{ firewall_limit_ssh_seconds }} --hitcount {{ firewall_limit_ssh_hitcount }} --name SSH --rsource -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables SSH BRUTE] " --log-level info +-A LIMIT_SSH -p tcp -m tcp -m recent --update --seconds {{ firewall_limit_ssh_seconds }} --hitcount {{ firewall_limit_ssh_hitcount}} --name SSH --rsource -m comment --comment "rate limit ssh v6" -j REJECT --reject-with tcp-reset +-A LIMIT_SSH -j ACCEPT +{% endif %} {% if firewall_drop_icmp_flood %} -N ICMP_FLOOD -A ICMP_FLOOD -m recent --set --name ICMP --rsource -A ICMP_FLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables ICMP FLOOD] " --log-level info --A ICMP_FLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -j DROP +-A ICMP_FLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m comment --comment "drop icmp flood v6" -j REJECT --reject-with icmp6-adm-prohibited -A ICMP_FLOOD -j ACCEPT {% endif %} -A INPUT -i lo -m comment --comment "lo accept all" -j ACCEPT -{% for ipset in firewall_ipset_mgmt.v6 | default([]) %} --A INPUT -p tcp -m tcp --dport 22 -m set --match-set mgmt_v6 src -m comment --comment "accept mgmt ssh" -j ACCEPT -{% endfor %} +-A INPUT -m state --state INVALID -m comment --comment "drop invalid IPv6" -j DROP -{% for ipset in firewall_ipset_blacklist.v6 | default([]) %} +{% if firewall_ipset_mgmt.v6 is defined %} +-A INPUT -p tcp -m tcp --dport 22 -m set --match-set mgmt_v6 src -m comment --comment "accept mgmt ssh" -j ACCEPT +{% endif %} + +{% if firewall_ipset_blacklist.v6 is defined %} -A INPUT -m set --match-set mgmt_v6 src -m comment --comment "drop blacklist" -j LOG_DROP -{% endfor %} +{% endif %} -A INPUT -s fe80::/10 -p icmpv6 -m icmpv6 --icmpv6-type 130 -m comment --comment "accept icmp 130" -j ACCEPT -A INPUT -s fe80::/10 -p icmpv6 -m icmpv6 --icmpv6-type 131 -m comment --comment "accept icmp 131" -j ACCEPT @@ -70,22 +71,24 @@ -A INPUT -p icmpv6 -m icmpv6 --icmpv6-type 148 -m hl --hl-eq 255 -m comment --comment "accept icmp 148" -j ACCEPT -A INPUT -p icmpv6 -m icmpv6 --icmpv6-type 149 -m hl --hl-eq 255 -m comment --comment "accept icmp 149" -j ACCEPT -{% for ipset in firewall_ipset_bogons | default([]) %} +{% if firewall_ipset_bogons.v6 is defined %} -A INPUT -i {{ firewall_bogon_interface }} -m set --match-set bogons_v6 src,dst -m comment --comment "drop bogons" -j LOG_DROP -{% endfor %} +{% endif %} + +{% if firewall_limit_ssh %} +-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m comment --comment "accept ssh" -j LIMIT_SSH +{% else %} +-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m comment --comment "accept ssh" -j ACCEPT +{% endif %} {% for port in firewall_allowed_tcp_ports.v6 | default([]) %} -A INPUT -p tcp -m tcp --dport {{ port }} -m comment --comment "accept {{ port }}/tcp" -j ACCEPT {% endfor %} -{% for port in firewall_allowed_udp_ports.v4 | default([]) %} +{% for port in firewall_allowed_udp_ports.v6 | default([]) %} -A INPUT -p udp -m udp --dport {{ port }} -m comment --comment "accept {{ port }}/udp" -j ACCEPT {% endfor %} -{% for port in firewall_limited_tcp_ports.v6 | default([]) %} --A INPUT -p tcp -m tcp --dport {{ port }} -m comment --comment "limit {{ port }}/tcp" -j LIMIT -{% endfor %} - -A INPUT -m state --state RELATED,ESTABLISHED -m comment --comment "accept related/established" -j ACCEPT -A INPUT -m comment --comment "log drop" -j LOG_DROP diff --git a/roles/firewall/templates/iptables.j2 b/roles/firewall/templates/iptables.j2 index c945e63..7060b40 100644 --- a/roles/firewall/templates/iptables.j2 +++ b/roles/firewall/templates/iptables.j2 @@ -3,46 +3,47 @@ :FORWARD {{ firewall_iptables_forward_policy }} :OUTPUT {{ firewall_iptables_output_policy }} -:LIMIT - - -:LOG_LIMIT - -:LOG_ACCEPT - -:LOG_DROP - - +-N LOG_ACCEPT -A LOG_ACCEPT -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables ACCEPT] " --log-level info -A LOG_ACCEPT -j ACCEPT +-N LOG_DROP -A LOG_DROP -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables DROP] " --log-level info --A LOG_DROP -j DROP +-A LOG_DROP -p tcp -m tcp -m comment --comment "reject tcp" -j REJECT --reject-with tcp-reset +-A LOG_DROP -p udp -m udp -m comment --comment "drop udp" -j DROP +-A LOG_DROP -m comment --comment "reject all" -j REJECT --reject-with icmp-admin-prohibited --A LOG_LIMIT -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables LIMIT] " --log-level info --A LOG_LIMIT -j DROP - --A LIMIT -m state --state NEW -m recent --set --A LIMIT -m state --state NEW -m recent --update --seconds {{ firewall_limit_seconds }} --hitcount {{ firewall_limit_hitcount }} -j LOG_LIMIT --A LIMIT -j ACCEPT +{% if firewall_limit_ssh %} +-N LIMIT_SSH +-A LIMIT_SSH -m recent --set --name SSH --rsource +-A LIMIT_SSH -m recent --update --seconds {{ firewall_limit_ssh_seconds }} --hitcount {{ firewall_limit_ssh_hitcount }} --name SSH --rsource -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables SSH BRUTE] " --log-level info +-A LIMIT_SSH -p tcp -m tcp -m recent --update --seconds {{ firewall_limit_ssh_seconds }} --hitcount {{ firewall_limit_ssh_hitcount }} --name SSH --rsource -m comment --comment "rate limit ssh v4" -j REJECT --reject-with tcp-reset +-A LIMIT_SSH -j ACCEPT +{% endif %} {% if firewall_drop_icmp_flood %} -N ICMP_FLOOD -A ICMP_FLOOD -m recent --set --name ICMP --rsource -A ICMP_FLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m limit --limit {{ firewall_log_limit }} --limit-burst {{ firewall_log_limit_burst }} -j LOG --log-prefix "[iptables ICMP FLOOD] " --log-level info --A ICMP_FLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -j DROP +-A ICMP_FLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m comment --comment "drop icmp flood v4" -j REJECT --reject-with icmp-admin-prohibited -A ICMP_FLOOD -j ACCEPT {% endif %} -A INPUT -i lo -m comment --comment "lo accept all" -j ACCEPT -{% for ipset in firewall_ipset_mgmt.v4 | default([]) %} +-A INPUT -m state --state INVALID -m comment --comment "drop invalid IPv4" -j DROP + +{% if firewall_ipset_mgmt.v4 is defined %} -A INPUT -p tcp -m tcp --dport 22 -m set --match-set mgmt_v4 src -m comment --comment "accept mgmt ssh" -j ACCEPT -{% endfor %} +{% endif %} -{% for ipset in firewall_ipset_blacklist.v4 | default([]) %} +{% if firewall_ipset_blacklist.v4 is defined %} -A INPUT -m set --match-set mgmt_v4 src -m comment --comment "drop blacklist" -j LOG_DROP -{% endfor %} +{% endif %} -{% for ipset in firewall_ipset_bogons | default([]) %} +{% if firewall_ipset_bogons.v4 is defined %} -A INPUT -i {{ firewall_bogon_interface }} -m set --match-set bogons_v4 src,dst -m comment --comment "drop bogons" -j LOG_DROP -{% endfor %} +{% endif %} -A INPUT -p icmp -m icmp --icmp-type destination-unreachable -m comment --comment "accept icmp destination-unreachable" -j ACCEPT -A INPUT -p icmp -m icmp --icmp-type time-exceeded -m comment --comment "accept icmp time-exceeded" -j ACCEPT @@ -58,6 +59,12 @@ -A INPUT -p icmp -m icmp --icmp-type {{ type }} -m comment --comment "accept icmp {{ type }}" -j ACCEPT {% endfor %} +{% if firewall_limit_ssh %} +-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m comment --comment "accept ssh" -j LIMIT_SSH +{% else %} +-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m comment --comment "accept ssh" -j ACCEPT +{% endif %} + {% for port in firewall_allowed_tcp_ports.v4 | default([]) %} -A INPUT -p tcp -m tcp --dport {{ port }} -m comment --comment "accept {{ port }}/tcp" -j ACCEPT {% endfor %} @@ -66,10 +73,6 @@ -A INPUT -p udp -m udp --dport {{ port }} -m comment --comment "accept {{ port }}/udp" -j ACCEPT {% endfor %} -{% for port in firewall_limited_tcp_ports.v4 | default([]) %} --A INPUT -p tcp -m tcp --dport {{ port }} -m comment --comment "limit {{ port }}/tcp" -j LIMIT -{% endfor %} - -A INPUT -m state --state RELATED,ESTABLISHED -m comment --comment "accept related/established" -j ACCEPT -A INPUT -m comment --comment "log drop" -j LOG_DROP