Files
firewall/templates/firewall.j2
T
2026-05-27 19:13:33 +02:00

211 lines
7.1 KiB
Django/Jinja

#!/bin/sh
#
# firewall script
# <ludovic.cartier@brainsys.io>
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
IPT4=/sbin/iptables
IPT6=/sbin/ip6tables
NAME=firewall
DESC="packet filter"
PUBIF="{{ firewall_public_interface | default(ansible_default_ipv4.interface | default('eth0')) }}"
FIREWALL_DOCKER_SAFE="{{ firewall_docker_safe | default(true) | ternary('1', '0') }}"
#PRIVATEIF=eth1
case "$1" in
start)
echo -n "Initializing $DESC. \n"
### IPv4 ###
echo " \033[33mIPv4 : \033[0m"
HAS_DOCKER4=0
if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT4 -S DOCKER >/dev/null 2>&1; then
HAS_DOCKER4=1
fi
# Reset only chains managed by this role.
$IPT4 -F INPUT
$IPT4 -F OUTPUT
$IPT4 -F ADMIN >/dev/null 2>&1 || true
$IPT4 -X ADMIN >/dev/null 2>&1 || true
if [ "$HAS_DOCKER4" -eq 0 ]; then
$IPT4 -F FORWARD
$IPT4 -P FORWARD DROP
else
echo " * Docker detected, preserving IPv4 FORWARD chain : \033[32m[OK] \033[0m"
fi
# DROP all incomming traffic
$IPT4 -P INPUT DROP
$IPT4 -P OUTPUT DROP
echo " * Deny all input and output IPv4 connections : \033[32m[OK] \033[0m"
# Unlimited access to loopback
$IPT4 -A INPUT -j ACCEPT -i lo
$IPT4 -A OUTPUT -j ACCEPT -o lo
echo " * Accept all loopback connections : \033[32m[OK] \033[0m"
# Allow full outgoing connection but no incomming stuff
$IPT4 -A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED
$IPT4 -A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED -m comment --comment "Authorize all established output access"
echo " * Don't break IPv4 established connections : \033[32m[OK] \033[0m"
# Allow incoming ICMP ping pong stuff
$IPT4 -A INPUT -j ACCEPT -p icmp --icmp-type echo-request
$IPT4 -A OUTPUT -j ACCEPT -p icmp --icmp-type echo-reply
echo " * Accept request & reply ICMP requests : \033[32m[OK] \033[0m"
## Protection rules
# Drop excessive RST packets
$IPT4 -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT
echo " * IPv4 protection rules : \033[32m[OK] \033[0m"
# Admin chain
$IPT4 -N ADMIN
{% for source in firewall_admin_sources %}
$IPT4 -A ADMIN -s {{ source.cidr }} -j ACCEPT -m comment --comment "{{ source.comment }}"
{% endfor %}
echo " * Creating admin chain : \033[32m[OK] \033[0m"
# Custom rules
{% for rule in firewall_admin_rules_ipv4 %}
$IPT4 -A INPUT -j ADMIN -p {{ rule.proto }} --dport {{ rule.dport }}{% if rule.proto == 'tcp' %} --syn{% endif %} -m comment --comment "{{ rule.comment }}"
{% endfor %}
{% for port in firewall_public_tcp_ports_ipv4 %}
$IPT4 -A INPUT -j ACCEPT -p tcp --dport {{ port }} -m comment --comment "IPv4 tcp/{{ port }}"
{% endfor %}
echo " * Custom IPv4 rules : \033[32m[OK] \033[0m"
# REJECT everything else
$IPT4 -A INPUT -j REJECT --reject-with tcp-reset -p tcp
$IPT4 -A INPUT -j REJECT -p udp
echo " * Reject everything else : \033[32m[OK] \033[0m"
### IPv6 ###
echo " \033[33mIPv6 : \033[0m"
HAS_DOCKER6=0
if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT6 -S DOCKER >/dev/null 2>&1; then
HAS_DOCKER6=1
fi
# Reset only chains managed by this role.
$IPT6 -F INPUT
$IPT6 -F OUTPUT
if [ "$HAS_DOCKER6" -eq 0 ]; then
$IPT6 -F FORWARD
$IPT6 -P FORWARD DROP
else
echo " * Docker detected, preserving IPv6 FORWARD chain : \033[32m[OK] \033[0m"
fi
# DROP all incomming traffic
$IPT6 -P INPUT DROP
$IPT6 -P OUTPUT DROP
echo " * Deny all input and output IPv6 connections : \033[32m[OK] \033[0m"
# Unlimited access to loopback
$IPT6 -A INPUT -j ACCEPT -i lo
$IPT6 -A OUTPUT -j ACCEPT -o lo
echo " * Accept all loopback connections : \033[32m[OK] \033[0m"
# Allow full outgoing connection but no incomming stuff
$IPT6 -A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED
$IPT6 -A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED -m comment --comment "Authorize all established output access"
echo " * Don't break IPv6 established connections : \033[32m[OK] \033[0m"
# Allow incoming ICMP ping pong stuff
#$IPT6 -A INPUT -j ACCEPT -p icmpv6 --icmpv6-type echo-request
#$IPT6 -A OUTPUT -j ACCEPT -p icmpv6 --icmpv6-type echo-reply
$IPT6 -A INPUT -j ACCEPT -p icmpv6
$IPT6 -A OUTPUT -j ACCEPT -p icmpv6
echo " * Accept request & reply ICMP requests : \033[32m[OK] \033[0m"
## Protection rules
# Drop excessive RST packets
$IPT6 -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT
echo " * IPv6 protection rules : \033[32m[OK] \033[0m"
# Custom rules
{% for port in firewall_public_tcp_ports_ipv6 %}
$IPT6 -A INPUT -j ACCEPT -p tcp --dport {{ port }} --syn -m comment --comment "IPv6 tcp/{{ port }}"
{% endfor %}
echo " * Custom IPv6 rules : \033[32m[OK] \033[0m"
# REJECT everything else
$IPT6 -A INPUT -j REJECT --reject-with tcp-reset -p tcp
$IPT6 -A INPUT -j REJECT -p udp
echo " * Reject everything else : \033[32m[OK] \033[0m"
# Log everything else
#$IPT6 -A INPUT -i $PUBIF -j LOG --log-prefix "Firewall IPv6 : "
;;
stop)
echo -n "Resetting $DESC. \n"
HAS_DOCKER4=0
if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT4 -S DOCKER >/dev/null 2>&1; then
HAS_DOCKER4=1
fi
HAS_DOCKER6=0
if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT6 -S DOCKER >/dev/null 2>&1; then
HAS_DOCKER6=1
fi
### IPv4 ###
$IPT4 -F INPUT
$IPT4 -F OUTPUT
$IPT4 -F ADMIN >/dev/null 2>&1 || true
$IPT4 -X ADMIN >/dev/null 2>&1 || true
if [ "$HAS_DOCKER4" -eq 0 ]; then
$IPT4 -F FORWARD
$IPT4 -P FORWARD ACCEPT
else
echo " * Docker detected, preserving IPv4 FORWARD chain : \033[32m[OK] \033[0m"
fi
$IPT4 -P INPUT ACCEPT
$IPT4 -P OUTPUT ACCEPT
echo " * Cleaning IPv4 chains and rules : \033[32m[OK] \033[0m"
### IPv6 ###
$IPT6 -F INPUT
$IPT6 -F OUTPUT
if [ "$HAS_DOCKER6" -eq 0 ]; then
$IPT6 -F FORWARD
$IPT6 -P FORWARD ACCEPT
else
echo " * Docker detected, preserving IPv6 FORWARD chain : \033[32m[OK] \033[0m"
fi
$IPT6 -P INPUT ACCEPT
$IPT6 -P OUTPUT ACCEPT
echo " * Cleaning IPv6 chains and rules : \033[32m[OK] \033[0m"
echo
;;
restart|force-reload)
$0 stop
$0 start
;;
status)
echo "\033[33mIPv4 chains and rules : \033[0m"
$IPT4 -L -n -v
echo
echo "\033[33mIPv6 chains and rules : \033[0m"
$IPT6 -L -n -v
;;
*)
echo "Usage: firewall {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0