From ba90203f219b96093f2b748a0deefe7cf8ae1a16 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Tue, 15 Mar 2022 23:07:33 +0100 Subject: [PATCH] minifirewall: upstream release 22.03.1 and use includes directory --- CHANGELOG.md | 1 + minifirewall/defaults/main.yml | 12 +- minifirewall/files/minifirewall | 845 +++++++++++++++++++++++++ minifirewall/files/minifirewall.conf | 106 ++-- minifirewall/tasks/config.yml | 65 +- minifirewall/tasks/install.yml | 14 +- minifirewall/tasks/main.yml | 6 + minifirewall/tasks/tail.yml | 14 +- minifirewall/templates/minifirewall.j2 | 492 -------------- 9 files changed, 971 insertions(+), 584 deletions(-) create mode 100755 minifirewall/files/minifirewall delete mode 100755 minifirewall/templates/minifirewall.j2 diff --git a/CHANGELOG.md b/CHANGELOG.md index fac22e94..96cb6838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * evolinux-base: backup-server-state release 22.03 * evolinux-base: Add non-free repos & install non-free firmware on dedicated hardware * generate-ldif: Add services check for bkctld +* minifirewall: upstream release 22.03.1 and use includes directory ### Fixed diff --git a/minifirewall/defaults/main.yml b/minifirewall/defaults/main.yml index fd4e726b..51d169cb 100644 --- a/minifirewall/defaults/main.yml +++ b/minifirewall/defaults/main.yml @@ -1,13 +1,19 @@ --- -minifirewall_main_file: /etc/default/minifirewall -minifirewall_tail_file: /etc/default/minifirewall.tail +# Deprecated variable +# minifirewall_main_file: /etc/default/minifirewall + +minifirewall_tail_file: zzz-tail minifirewall_tail_included: False minifirewall_tail_force: True +# Overwrite files completely minifirewall_force_upgrade_script: False minifirewall_force_upgrade_config: False +# Update specific values in configuration +minifirewall_update_config: True + minifirewall_git_url: "https://forge.evolix.org/minifirewall.git" minifirewall_checkout_path: "/tmp/minifirewall" minifirewall_int: "{{ ansible_default_ipv4.interface }}" @@ -31,7 +37,7 @@ minifirewall_private_ports_tcp: [5666] minifirewall_private_ports_udp: [] # Keep a null value to leave the setting as is -# otherwise use an Array, eg. "minifirewall_ssh_ok: ['0.0.0.0/0']" +# otherwise use an Array, eg. "minifirewall_ssh_ok: ['0.0.0.0/0', '::/0']" minifirewall_dns_servers: Null minifirewall_http_sites: Null minifirewall_https_sites: Null diff --git a/minifirewall/files/minifirewall b/minifirewall/files/minifirewall new file mode 100755 index 00000000..b1595471 --- /dev/null +++ b/minifirewall/files/minifirewall @@ -0,0 +1,845 @@ +#!/bin/sh + +# minifirewall is shellscripts for easy firewalling on a standalone server +# we used netfilter/iptables http://netfilter.org/ designed for recent Linux kernel +# See https://gitea.evolix.org/evolix/minifirewall + +# Copyright (c) 2007-2022 Evolix +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 +# of the License. + +# Description +# script for standalone server + +# Start or stop minifirewall +# + +### BEGIN INIT INFO +# Provides: minifirewall +# Required-Start: +# Required-Stop: +# Should-Start: $network $syslog $named +# Should-Stop: $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: start and stop the firewall +# Description: Firewall designed for standalone server +### END INIT INFO + +VERSION="22.03.1" + +NAME="minifirewall" +DESC="Firewall designed for standalone server" + +set -u + +# Variables configuration +######################### + +config_file="/etc/default/minifirewall" +includes_dir="/etc/minifirewall.d" + +# iptables paths +IPT=$(command -v iptables) +if [ -z "${IPT}" ]; then + echo "Unable to find 'iptables\` command in PATH." >&2 + exit 1 +fi +IPT6=$(command -v ip6tables) +if [ -z "${IPT6}" ]; then + echo "Unable to find 'ip6tables\` command in PATH." >&2 + exit 1 +fi + +# TCP/IP variables +LOOPBACK='127.0.0.0/8' +CLASSA='10.0.0.0/8' +CLASSB='172.16.0.0/12' +CLASSC='192.168.0.0/16' +CLASSD='224.0.0.0/4' +CLASSE='240.0.0.0/5' +ALL='0.0.0.0' +BROAD='255.255.255.255' +PORTSROOT='0:1023' +PORTSUSER='1024:65535' + +# Configuration + +INT='' +IPV6='' +DOCKER='' +INTLAN='' +TRUSTEDIPS='' +PRIVILEGIEDIPS='' +SERVICESTCP1p='' +SERVICESUDP1p='' +SERVICESTCP1='' +SERVICESUDP1='' +SERVICESTCP2='' +SERVICESUDP2='' +SERVICESTCP3='' +SERVICESUDP3='' +DNSSERVEURS='' +HTTPSITES='' +HTTPSSITES='' +FTPSITES='' +SSHOK='' +SMTPOK='' +SMTPSECUREOK='' +NTPOK='' +PROXY='' +PROXYBYPASS='' +PROXYPORT='' +BACKUPSERVERS='' + +LEGACY_CONFIG='off' + +is_ipv6_enabled() { + test "${IPV6}" != "off" +} +is_docker_enabled() { + test "${DOCKER}" = "on" +} +is_proxy_enabled() { + test "${PROXY}" = "on" +} +is_ipv6() { + echo "$1" | grep -q ':' +} +is_legacy_config() { + test "${LEGACY_CONFIG}" != "off" +} +chain_exists() { + chain_name="$1" + if [ $# -ge 2 ]; then + intable="--table $2" + fi + # shellcheck disable=SC2086 + iptables ${intable} -nL "${chain_name}" >/dev/null 2>&1 +} +source_file_or_error() { + file=$1 + echo "...sourcing '${file}\`" + + tmpfile=$(mktemp --tmpdir=/tmp minifirewall.XXX) + . "${file}" 2>"${tmpfile}" >&2 + + if [ -s "${tmpfile}" ]; then + echo "${file} returns standard or error output (see below). Stopping." >&2 + cat "${tmpfile}" + exit 1 + fi + rm "${tmpfile}" +} +source_configuration() { + if ! test -f ${config_file}; then + echo "${config_file} does not exist" >&2 + + ## We still want to deal with this really old configuration file + ## even if it has been deprecated since Debian 8 + old_config_file="/etc/firewall.rc" + if test -f ${old_config_file}; then + echo "${old_config_file} is deprecated. Rename it to ${config_file}" >&2 + fi + + exit 1 + fi + + if grep -e "iptables" -e "ip6tables" "${config_file}" | grep -qvE "^#"; then + # Backward compatible mode + ########################### + + echo "Legacy config detected" + LEGACY_CONFIG='on' + + # Non-backward compatible mode + ############################### + + # If we ever want to remove the backward compatible mode + # we can remove the two lines above and uncomment the lines below. + # They break if any iptables/ip6tables command is found in the configuration file + + # echo "iptables/ip6tables commands found in ${config_file}." >&2 + # echo "Move them in included files (in ${includes_dir})." >&2 + # exit 1 + fi + + if is_legacy_config; then + # In this mode, we extract all variable definitions + # to a temporary file that we can source. + # It allow iptables/ip6tables commands to remain in the configuration file + # and not interfere with the configuration step. + + tmp_config_file=$(mktemp --tmpdir=/tmp minifirewall.XXX) + grep -E "^\s*[_a-zA-Z0-9]+=" "${config_file}" > "${tmp_config_file}" + + source_file_or_error "${tmp_config_file}" + rm "${tmp_config_file}" + else + source_file_or_error "${config_file}" + fi +} +source_includes() { + if [ -d "${includes_dir}" ]; then + include_files=$(find ${includes_dir} -type f -readable -not -name '*.*' | sort -h) + for include_file in ${include_files}; do + source_file_or_error "${include_file}" + done + fi +} + +start() { + echo "Start IPTables rules..." + + # Stop and warn if error! + set -e + trap 'echo "ERROR in minifirewall configuration (fix it now!) or script manipulation (fix yourself)." ' INT TERM EXIT + + # sysctl network security settings + ################################## + + # Set 1 to ignore broadcast pings (default) + : "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS:=1}" + # Set 1 to ignore bogus ICMP responses (default) + : "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES:=1}" + # Set 0 to disable source routing (default) + : "${SYSCTL_ACCEPT_SOURCE_ROUTE:=0}" + # Set 1 to enable TCP SYN cookies (default) + # cf http://cr.yp.to/syncookies.html + : "${SYSCTL_TCP_SYNCOOKIES:=1}" + # Set 0 to disable ICMP redirects (default) + : "${SYSCTL_ICMP_REDIRECTS:=0}" + # Set 1 to enable Reverse Path filtering (default) + # Set 0 if VRRP is used + : "${SYSCTL_RP_FILTER:=1}" + # Set 1 to log packets with inconsistent address (default) + : "${SYSCTL_LOG_MARTIANS:=1}" + + if [ "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}" = "1" ] || [ "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}" = "0" ]; then + echo "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts + else + echo "Invalid SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS value '${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}', must be '0' or '1'." >&2 + exit 1 + fi + + if [ "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}" = "1" ] || [ "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}" = "0" ]; then + echo "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses + else + echo "Invalid SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES value '${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}', must be '0' or '1'." >&2 + exit 1 + fi + + if [ "${SYSCTL_ACCEPT_SOURCE_ROUTE}" = "1" ] || [ "${SYSCTL_ACCEPT_SOURCE_ROUTE}" = "0" ]; then + for proc_sys_file in /proc/sys/net/ipv4/conf/*/accept_source_route; do + echo "${SYSCTL_ACCEPT_SOURCE_ROUTE}" = > "${proc_sys_file}" + done + else + echo "Invalid SYSCTL_ACCEPT_SOURCE_ROUTE value '${SYSCTL_ACCEPT_SOURCE_ROUTE}', must be '0' or '1'." >&2 + exit 1 + fi + + if [ "${SYSCTL_TCP_SYNCOOKIES}" = "1" ] || [ "${SYSCTL_TCP_SYNCOOKIES}" = "0" ]; then + echo "${SYSCTL_TCP_SYNCOOKIES}" > /proc/sys/net/ipv4/tcp_syncookies + else + echo "Invalid SYSCTL_TCP_SYNCOOKIES value '${SYSCTL_TCP_SYNCOOKIES}', must be '0' or '1'." >&2 + exit 1 + fi + + if [ "${SYSCTL_ICMP_REDIRECTS}" = "1" ] || [ "${SYSCTL_ICMP_REDIRECTS}" = "0" ]; then + for proc_sys_file in /proc/sys/net/ipv4/conf/*/accept_redirects; do + echo "${SYSCTL_ICMP_REDIRECTS}" > "${proc_sys_file}" + done + for proc_sys_file in /proc/sys/net/ipv4/conf/*/send_redirects; do + echo "${SYSCTL_ICMP_REDIRECTS}" > "${proc_sys_file}" + done + else + echo "Invalid SYSCTL_ICMP_REDIRECTS value '${SYSCTL_ICMP_REDIRECTS}', must be '0' or '1'." >&2 + exit 1 + fi + + if [ "${SYSCTL_RP_FILTER}" = "1" ] || [ "${SYSCTL_RP_FILTER}" = "0" ]; then + for proc_sys_file in /proc/sys/net/ipv4/conf/*/rp_filter; do + echo "${SYSCTL_RP_FILTER}" > "${proc_sys_file}" + done + else + echo "Invalid SYSCTL_RP_FILTER value '${SYSCTL_RP_FILTER}', must be '0' or '1'." >&2 + exit 1 + fi + + if [ "${SYSCTL_LOG_MARTIANS}" = "1" ] || [ "${SYSCTL_LOG_MARTIANS}" = "0" ]; then + for proc_sys_file in /proc/sys/net/ipv4/conf/*/log_martians; do + echo "${SYSCTL_LOG_MARTIANS}" > "${proc_sys_file}" + done + else + echo "Invalid SYSCTL_LOG_MARTIANS value '${SYSCTL_LOG_MARTIANS}', must be '0' or '1'." >&2 + exit 1 + fi + + # IPTables configuration + ######################## + + ${IPT} -N LOG_DROP + ${IPT} -A LOG_DROP -j LOG --log-prefix '[IPTABLES DROP] : ' + ${IPT} -A LOG_DROP -j DROP + ${IPT} -N LOG_ACCEPT + ${IPT} -A LOG_ACCEPT -j LOG --log-prefix '[IPTABLES ACCEPT] : ' + ${IPT} -A LOG_ACCEPT -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -N LOG_DROP + ${IPT6} -A LOG_DROP -j LOG --log-prefix '[IPTABLES DROP] : ' + ${IPT6} -A LOG_DROP -j DROP + ${IPT6} -N LOG_ACCEPT + ${IPT6} -A LOG_ACCEPT -j LOG --log-prefix '[IPTABLES ACCEPT] : ' + ${IPT6} -A LOG_ACCEPT -j ACCEPT + fi + + # Trusted ip addresses + ${IPT} -N ONLYTRUSTED + ${IPT} -A ONLYTRUSTED -j LOG_DROP + if is_ipv6_enabled; then + ${IPT6} -N ONLYTRUSTED + ${IPT6} -A ONLYTRUSTED -j LOG_DROP + fi + for ip in ${TRUSTEDIPS}; do + if is_ipv6 ${ip}; then + if is_ipv6_enabled; then + ${IPT6} -I ONLYTRUSTED -s ${ip} -j ACCEPT + fi + else + ${IPT} -I ONLYTRUSTED -s ${ip} -j ACCEPT + fi + done + + # Privilegied ip addresses + # (trusted ip addresses *are* privilegied) + ${IPT} -N ONLYPRIVILEGIED + ${IPT} -A ONLYPRIVILEGIED -j ONLYTRUSTED + if is_ipv6_enabled; then + ${IPT6} -N ONLYPRIVILEGIED + ${IPT6} -A ONLYPRIVILEGIED -j ONLYTRUSTED + fi + for ip in ${PRIVILEGIEDIPS}; do + if is_ipv6 ${ip}; then + if is_ipv6_enabled; then + ${IPT6} -I ONLYPRIVILEGIED -s ${ip} -j ACCEPT + fi + else + ${IPT} -I ONLYPRIVILEGIED -s ${ip} -j ACCEPT + fi + done + + # Chain for restrictions (blacklist IPs/ranges) + ${IPT} -N NEEDRESTRICT + if is_ipv6_enabled; then + ${IPT6} -N NEEDRESTRICT + fi + + # We allow all on loopback interface + ${IPT} -A INPUT -i lo -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -A INPUT -i lo -j ACCEPT + fi + # if OUTPUTDROP + ${IPT} -A OUTPUT -o lo -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -A OUTPUT -o lo -j ACCEPT + fi + + # We avoid "martians" packets, typical when W32/Blaster virus + # attacked windowsupdate.com and DNS was changed to 127.0.0.1 + # ${IPT} -t NAT -I PREROUTING -s ${LOOPBACK} -i ! lo -j DROP + for IP in ${LOOPBACK}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -s ${IP} ! -i lo -j DROP + fi + else + ${IPT} -A INPUT -s ${IP} ! -i lo -j DROP + fi + done + + if is_docker_enabled; then + # WARN: IPv6 not yet supported for Docker rules + ${IPT} -N MINIFW-DOCKER-TRUSTED + ${IPT} -A MINIFW-DOCKER-TRUSTED -j DROP + + ${IPT} -N MINIFW-DOCKER-PRIVILEGED + ${IPT} -A MINIFW-DOCKER-PRIVILEGED -j MINIFW-DOCKER-TRUSTED + ${IPT} -A MINIFW-DOCKER-PRIVILEGED -j RETURN + + ${IPT} -N MINIFW-DOCKER-PUB + ${IPT} -A MINIFW-DOCKER-PUB -j MINIFW-DOCKER-PRIVILEGED + ${IPT} -A MINIFW-DOCKER-PUB -j RETURN + + # Flush DOCKER-USER if exist, create it if absent + if chain_exists 'DOCKER-USER'; then + ${IPT} -F DOCKER-USER + else + ${IPT} -N DOCKER-USER + fi; + + # Pipe new connection through MINIFW-DOCKER-PUB + ${IPT} -A DOCKER-USER -i ${INT} -m state --state NEW -j MINIFW-DOCKER-PUB + ${IPT} -A DOCKER-USER -j RETURN + fi + + + # Local services restrictions + ############################# + + # Allow services for ${INTLAN} (local server or local network) + for IP in ${INTLAN}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -s ${IP} -j ACCEPT + fi + else + ${IPT} -A INPUT -s ${IP} -j ACCEPT + fi + done + + # Enable protection chain for sensible services + for port in ${SERVICESTCP1p}; do + ${IPT} -A INPUT -p tcp --dport ${port} -j NEEDRESTRICT + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp --dport ${port} -j NEEDRESTRICT + fi + done + + for port in ${SERVICESUDP1p}; do + ${IPT} -A INPUT -p udp --dport ${port} -j NEEDRESTRICT + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p udp --dport ${port} -j NEEDRESTRICT + fi + done + + # Public service + for port in ${SERVICESTCP1}; do + ${IPT} -A INPUT -p tcp --dport ${port} -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp --dport ${port} -j ACCEPT + fi + done + + for port in ${SERVICESUDP1}; do + ${IPT} -A INPUT -p udp --dport ${port} -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p udp --dport ${port} -j ACCEPT + fi + done + + # Privilegied services + for port in ${SERVICESTCP2}; do + ${IPT} -A INPUT -p tcp --dport ${port} -j ONLYPRIVILEGIED + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp --dport ${port} -j ONLYPRIVILEGIED + fi + done + + for port in ${SERVICESUDP2}; do + ${IPT} -A INPUT -p udp --dport ${port} -j ONLYPRIVILEGIED + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p udp --dport ${port} -j ONLYPRIVILEGIED + fi + done + + # Private services + for port in ${SERVICESTCP3}; do + ${IPT} -A INPUT -p tcp --dport ${port} -j ONLYTRUSTED + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp --dport ${port} -j ONLYTRUSTED + fi + done + + for port in ${SERVICESUDP3}; do + ${IPT} -A INPUT -p udp --dport ${port} -j ONLYTRUSTED + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p udp --dport ${port} -j ONLYTRUSTED + fi + done + + + if is_docker_enabled; then + # WARN: IPv6 not yet supported + + # Public services defined in SERVICESTCP1 & SERVICESUDP1 + for dstport in ${SERVICESTCP1}; do + ${IPT} -I MINIFW-DOCKER-PUB -p tcp --dport "${dstport}" -j RETURN + done + + for dstport in ${SERVICESUDP1}; do + ${IPT} -I MINIFW-DOCKER-PUB -p udp --dport "${dstport}" -j RETURN + done + + # Privileged services (accessible from privileged & trusted IPs) + for dstport in ${SERVICESTCP2}; do + for srcip in ${PRIVILEGIEDIPS}; do + ${IPT} -I MINIFW-DOCKER-PRIVILEGED -p tcp -s "${srcip}" --dport "${dstport}" -j RETURN + done + + for srcip in ${TRUSTEDIPS}; do + ${IPT} -I MINIFW-DOCKER-PRIVILEGED -p tcp -s "${srcip}" --dport "${dstport}" -j RETURN + done + done + + for dstport in ${SERVICESUDP2}; do + for srcip in ${PRIVILEGIEDIPS}; do + ${IPT} -I MINIFW-DOCKER-PRIVILEGED -p udp -s "${srcip}" --dport "${dstport}" -j RETURN + done + + for srcip in ${TRUSTEDIPS}; do + ${IPT} -I MINIFW-DOCKER-PRIVILEGED -p udp -s "${srcip}" --dport "${dstport}" -j RETURN + done + done + + # Trusted services (accessible from trusted IPs) + for dstport in ${SERVICESTCP3}; do + for srcip in ${TRUSTEDIPS}; do + ${IPT} -I MINIFW-DOCKER-TRUSTED -p tcp -s "${srcip}" --dport "${dstport}" -j RETURN + done + done + + for dstport in ${SERVICESUDP3}; do + for srcip in ${TRUSTEDIPS}; do + ${IPT} -I MINIFW-DOCKER-TRUSTED -p udp -s "${srcip}" --dport "${dstport}" -j RETURN + done + done + fi + + # External services + ################### + + # DNS authorizations + for IP in ${DNSSERVEURS}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp ! --syn --sport 53 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + ${IPT6} -A INPUT -p udp --sport 53 --dport ${PORTSUSER} -s ${IP} -m state --state ESTABLISHED,RELATED -j ACCEPT + ${IPT6} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 53 --match state --state NEW -j ACCEPT + fi + else + ${IPT} -A INPUT -p tcp ! --syn --sport 53 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + ${IPT} -A INPUT -p udp --sport 53 --dport ${PORTSUSER} -s ${IP} -m state --state ESTABLISHED,RELATED -j ACCEPT + ${IPT} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 53 --match state --state NEW -j ACCEPT + fi + done + + # HTTP (TCP/80) authorizations + for IP in ${HTTPSITES}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp ! --syn --sport 80 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + else + ${IPT} -A INPUT -p tcp ! --syn --sport 80 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + done + + # HTTPS (TCP/443) authorizations + for IP in ${HTTPSSITES}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp ! --syn --sport 443 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + else + ${IPT} -A INPUT -p tcp ! --syn --sport 443 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + done + + # FTP (so complex protocol...) authorizations + for IP in ${FTPSITES}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + # requests on Control connection + ${IPT6} -A INPUT -p tcp ! --syn --sport 21 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + # FTP port-mode on Data Connection + ${IPT6} -A INPUT -p tcp --sport 20 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + # FTP passive-mode on Data Connection + # WARNING, this allow all connections on TCP ports > 1024 + ${IPT6} -A INPUT -p tcp ! --syn --sport ${PORTSUSER} --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + else + # requests on Control connection + ${IPT} -A INPUT -p tcp ! --syn --sport 21 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + # FTP port-mode on Data Connection + ${IPT} -A INPUT -p tcp --sport 20 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + # FTP passive-mode on Data Connection + # WARNING, this allow all connections on TCP ports > 1024 + ${IPT} -A INPUT -p tcp ! --syn --sport ${PORTSUSER} --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + done + + # SSH authorizations + for IP in ${SSHOK}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp ! --syn --sport 22 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + else + ${IPT} -A INPUT -p tcp ! --syn --sport 22 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + done + + # SMTP authorizations + for IP in ${SMTPOK}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp ! --syn --sport 25 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + else + ${IPT} -A INPUT -p tcp ! --syn --sport 25 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + done + + # secure SMTP (TCP/465 et TCP/587) authorizations + for IP in ${SMTPSECUREOK}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp ! --syn --sport 465 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + ${IPT6} -A INPUT -p tcp ! --syn --sport 587 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + else + ${IPT} -A INPUT -p tcp ! --syn --sport 465 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + ${IPT} -A INPUT -p tcp ! --syn --sport 587 --dport ${PORTSUSER} -s ${IP} -j ACCEPT + fi + done + + # NTP authorizations + for IP in ${NTPOK}; do + if is_ipv6 ${IP}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p udp --sport 123 -s ${IP} -j ACCEPT + ${IPT6} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 123 --match state --state NEW -j ACCEPT + fi + else + ${IPT} -A INPUT -p udp --sport 123 -s ${IP} -j ACCEPT + ${IPT} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 123 --match state --state NEW -j ACCEPT + fi + done + + # Proxy (Squid) + if is_proxy_enabled; then + # WARN: Squid only listen on IPv4 yet + # TODO: verify that the pattern used for IPv4 is relevant with IPv6 + + ${IPT} -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT + for dstip in ${PROXYBYPASS}; do + if ! is_ipv6 ${dstip}; then + ${IPT} -t nat -A OUTPUT -p tcp --dport 80 -d "${dstip}" -j ACCEPT + fi + done + ${IPT} -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port "${PROXYPORT:-'8888'}" + fi + + # Output for backup servers + for server in ${BACKUPSERVERS}; do + server_port=$(echo "${server}" | awk -F : '{print $(NF)}') + server_ip=$(echo "${server}" | sed -e "s/:${server_port}$//") + + if [ -n "${server_ip}" ] && [ -n "${server_port}" ]; then + if is_ipv6 ${server_ip}; then + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p tcp --sport "${server_port}" --dport 1024:65535 -s "${server_ip}" -m state --state ESTABLISHED,RELATED -j ACCEPT + fi + else + ${IPT} -A INPUT -p tcp --sport "${server_port}" --dport 1024:65535 -s "${server_ip}" -m state --state ESTABLISHED,RELATED -j ACCEPT + fi + else + echo "Unrecognized syntax for BACKUPSERVERS '${server}\`. Use space-separated IP:PORT tuples." >&2 + exit 1 + fi + done + + # Always allow ICMP + ${IPT} -A INPUT -p icmp -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -A INPUT -p icmpv6 -j ACCEPT + fi + + + # IPTables policy + ################# + + # by default DROP INPUT packets + ${IPT} -P INPUT DROP + if is_ipv6_enabled; then + ${IPT6} -P INPUT DROP + fi + + # by default, no FORWARDING (deprecated for Virtual Machines) + #echo 0 > /proc/sys/net/ipv4/ip_forward + #${IPT} -P FORWARD DROP + #${IPT6} -P FORWARD DROP + + # by default allow OUTPUT packets... but drop UDP packets (see OUTPUTDROP to drop OUTPUT packets) + ${IPT} -P OUTPUT ACCEPT + if is_ipv6_enabled; then + ${IPT6} -P OUTPUT ACCEPT + fi + + ${IPT} -A OUTPUT -o ${INT} -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -A OUTPUT -o ${INT} -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT + fi + + ${IPT} -A OUTPUT -p udp --match state --state ESTABLISHED,RELATED -j ACCEPT + if is_ipv6_enabled; then + ${IPT6} -A OUTPUT -p udp --match state --state ESTABLISHED,RELATED -j ACCEPT + fi + + ${IPT} -A OUTPUT -p udp -j DROP + if is_ipv6_enabled; then + ${IPT6} -A OUTPUT -p udp -j DROP + fi + + if is_legacy_config; then + source_file_or_error "${config_file}" + fi + + # Source files present in optional directory + source_includes + + trap - INT TERM EXIT + + echo "...starting IPTables rules is now finish : OK" +} + +stop() { + echo "Flush all rules and accept everything..." + + # Delete all rules + ${IPT} -F INPUT + if is_ipv6_enabled; then + ${IPT6} -F INPUT + fi + + ${IPT} -F OUTPUT + if is_ipv6_enabled; then + ${IPT6} -F OUTPUT + fi + + ${IPT} -F LOG_DROP + ${IPT} -F LOG_ACCEPT + ${IPT} -F ONLYTRUSTED + ${IPT} -F ONLYPRIVILEGIED + ${IPT} -F NEEDRESTRICT + if is_ipv6_enabled; then + ${IPT6} -F LOG_DROP + ${IPT6} -F LOG_ACCEPT + ${IPT6} -F ONLYTRUSTED + ${IPT6} -F ONLYPRIVILEGIED + ${IPT6} -F NEEDRESTRICT + fi + + ${IPT} -t mangle -F + if is_ipv6_enabled; then + ${IPT6} -t mangle -F + fi + + if is_docker_enabled; then + # WARN: IPv6 not yet supported + + ${IPT} -F DOCKER-USER + ${IPT} -A DOCKER-USER -j RETURN + + ${IPT} -F MINIFW-DOCKER-PUB + ${IPT} -X MINIFW-DOCKER-PUB + ${IPT} -F MINIFW-DOCKER-PRIVILEGED + ${IPT} -X MINIFW-DOCKER-PRIVILEGED + ${IPT} -F MINIFW-DOCKER-TRUSTED + ${IPT} -X MINIFW-DOCKER-TRUSTED + else + ${IPT} -t nat -F + fi + + # Accept all + ${IPT} -P INPUT ACCEPT + if is_ipv6_enabled; then + ${IPT6} -P INPUT ACCEPT + fi + + ${IPT} -P OUTPUT ACCEPT + if is_ipv6_enabled; then + ${IPT6} -P OUTPUT ACCEPT + fi + #${IPT} -P FORWARD ACCEPT + #${IPT} -t nat -P PREROUTING ACCEPT + #${IPT} -t nat -P POSTROUTING ACCEPT + + # Delete non-standard chains + ${IPT} -X LOG_DROP + ${IPT} -X LOG_ACCEPT + ${IPT} -X ONLYPRIVILEGIED + ${IPT} -X ONLYTRUSTED + ${IPT} -X NEEDRESTRICT + if is_ipv6_enabled; then + ${IPT6} -X LOG_DROP + ${IPT6} -X LOG_ACCEPT + ${IPT6} -X ONLYPRIVILEGIED + ${IPT6} -X ONLYTRUSTED + ${IPT6} -X NEEDRESTRICT + fi + + echo "...flushing IPTables rules is now finish : OK" +} + +status() { + ${IPT} -L -n -v --line-numbers + ${IPT} -t nat -L -n -v --line-numbers + ${IPT} -t mangle -L -n -v --line-numbers + ${IPT6} -L -n -v --line-numbers + ${IPT6} -t mangle -L -n -v --line-numbers +} + +reset() { + echo "Reset all IPTables counters..." + + ${IPT} -Z + if is_ipv6_enabled; then + ${IPT6} -Z + fi + + ${IPT} -t nat -Z + + ${IPT} -t mangle -Z + if is_ipv6_enabled; then + ${IPT6} -t mangle -Z + fi + + echo "...reseting IPTables counters is now finish : OK" +} + +echo "${NAME} version ${VERSION}" +source_configuration + +case "${1:-''}" in + start) + start + ;; + + stop) + stop + ;; + + status) + status + ;; + + reset) + reset + ;; + + restart) + stop + start + ;; + + *) + echo "Usage: $0 {start|stop|restart|status|reset}" + exit 1 + ;; +esac + +exit 0 diff --git a/minifirewall/files/minifirewall.conf b/minifirewall/files/minifirewall.conf index 47be78bf..1cd73d7f 100644 --- a/minifirewall/files/minifirewall.conf +++ b/minifirewall/files/minifirewall.conf @@ -1,31 +1,37 @@ # Configuration for minifirewall : https://gitea.evolix.org/evolix/minifirewall -# Version 20.12 — 2020-12-01 22:55:35 +# Version 22.03.1 — 2022-03-15 +# shellcheck shell=sh disable=SC2034 # Main interface INT='eth0' # IPv6 -IPV6=on +IPV6='on' # Docker Mode # Changes the behaviour of minifirewall to not break the containers' network # For instance, turning it on will disable nat table purge -# Also, we'll add the DOCKER-USER chain, in iptable +# Also, we'll add the DOCKER-USER chain, in iptables +# +# WARNING : If the port mapping is different between the host and the container +# (ie: Listen on :8090 on host, but :8080 in container) +# then you need to give the port used inside the container DOCKER='off' -# Trusted IPv4 local network -# ...will be often IP/32 if you don't trust anything -INTLAN='192.168.0.2/32' +# Trusted local network +# ...will be often IPv4/32 or IPv6/128 if you don't trust anything +INTLAN='192.0.2.1/32 2001:db8::1/128' -# Trusted IPv4 addresses for private and semi-public services -TRUSTEDIPS='31.170.9.129 62.212.121.90 31.170.8.4 82.65.34.85 54.37.106.210 51.210.84.146' +# Trusted IP addresses for private and semi-public services +# TODO: add all our IPv6 adresses +TRUSTEDIPS='31.170.9.129 2a01:9500:37:129::/64 62.212.121.90 31.170.8.4 2a01:9500::fada/128 82.65.34.85 54.37.106.210 51.210.84.146' -# Privilegied IPv4 addresses for semi-public services +# Privilegied IP addresses for semi-public services # (no need to add again TRUSTEDIPS) PRIVILEGIEDIPS='' -# Local services IPv4/IPv6 restrictions +# Local services IP restrictions ####################################### # Protected services @@ -45,62 +51,86 @@ SERVICESUDP2='' SERVICESTCP3='5666' SERVICESUDP3='' -# Standard output IPv4 access restrictions + +# Standard output IPv4/IPv6 access restrictions ########################################## # DNS authorizations # (if you have local DNS server, set 0.0.0.0/0) -DNSSERVEURS='0.0.0.0/0' +DNSSERVEURS='0.0.0.0/0 ::/0' # HTTP authorizations # (you can use DNS names but set cron to reload minifirewall regularly) # (if you have HTTP proxy, set 0.0.0.0/0) -# HTTPSITES='security.debian.org pub.evolix.net security-cdn.debian.org mirror.evolix.org backports.debian.org hwraid.le-vert.net antispam00.evolix.org spamassassin.apache.org sa-update.space-pro.be sa-update.secnap.net www.sa-update.pccc.com sa-update.dnswl.org ocsp.int-x3.letsencrypt.org' -HTTPSITES='0.0.0.0/0' +HTTPSITES='0.0.0.0/0 ::/0' # HTTPS authorizations -HTTPSSITES='0.0.0.0/0' +HTTPSSITES='0.0.0.0/0 ::/0' # FTP authorizations FTPSITES='' # SSH authorizations -SSHOK='0.0.0.0/0' +SSHOK='0.0.0.0/0 ::/0' # SMTP authorizations -SMTPOK='0.0.0.0/0' +SMTPOK='0.0.0.0/0 ::/0' # SMTP secure authorizations (ports TCP/465 and TCP/587) SMTPSECUREOK='' # NTP authorizations -NTPOK='0.0.0.0/0' +NTPOK='0.0.0.0/0 ::/0' + +# Proxy (Squid) +PROXY='off' +# (proxy port) +PROXYPORT='8888' +# (destinations that bypass the proxy) +PROXYBYPASS="${INTLAN} 127.0.0.0/8 ::1/128" + +# Backup servers +# (add IP:PORT for each one, example: '192.168.10.1:1234 192.168.10.2:5678') +BACKUPSERVERS='' -# IPv6 Specific rules +# Includes ##################### -# Example: allow SSH from Trusted IPv6 addresses -/sbin/ip6tables -A INPUT -i $INT -p tcp --dport 22 -s 2a01:9500:37:129::/64 -j ACCEPT +# Files in /etc/minifirewall.d/* (without "." in name) +# are automatically included in alphanumerical order. +# +# Within included files, you can use those helper functions : +# * is_ipv6_enabled: returns true if IPv6 is enabled, or false +# * is_docker_enabled: returns true if Docker mode is eabled, or false +# * is_proxy_enabled: returns true if Proxy mode is enabled , or false -# Example: allow outgoing SSH/HTTP/HTTPS/SMTP/DNS traffic -/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 22 --match state --state ESTABLISHED,RELATED -j ACCEPT -/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 80 --match state --state ESTABLISHED,RELATED -j ACCEPT -/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 443 --match state --state ESTABLISHED,RELATED -j ACCEPT -/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 25 --match state --state ESTABLISHED,RELATED -j ACCEPT -/sbin/ip6tables -A INPUT -i $INT -p udp --sport 53 --match state --state ESTABLISHED,RELATED -j ACCEPT -/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 53 --match state --state ESTABLISHED,RELATED -j ACCEPT -# Example: allow output DNS, NTP and traceroute traffic -/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 53 --match state --state NEW -j ACCEPT -/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 123 --match state --state NEW -j ACCEPT -#/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT +# Custom sysctl values (advanced) +################################# -# Example: allow DHCPv6 -/sbin/ip6tables -A INPUT -i $INT -p udp --dport 546 -d fe80::/64 -j ACCEPT -/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 547 -j ACCEPT +# In most cases, the default values set by minifirewall are good. +# If you really know what you are doing, +# you can uncomment some lines and customize the values. -# IPv4 Specific rules -##################### +# Set 1 to ignore broadcast pings (default) +# SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS='1' -# /sbin/iptables ... +# Set 1 to ignore bogus ICMP responses (default) +# SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES='1' + +# Set 0 to disable source routing (default) +# SYSCTL_ACCEPT_SOURCE_ROUTE='0' + +# Set 1 to enable TCP SYN cookies (default) +# SYSCTL_TCP_SYNCOOKIES='1' + +# Set 0 to disable ICMP redirects (default) +# SYSCTL_ICMP_REDIRECTS='0' + +# Set 1 to enable Reverse Path filtering (default) +# Set 0 if VRRP is used +# SYSCTL_RP_FILTER='1' + +# Set 1 to log packets with inconsistent address (default) +# SYSCTL_LOG_MARTIANS='1' \ No newline at end of file diff --git a/minifirewall/tasks/config.yml b/minifirewall/tasks/config.yml index 04ed3a9c..c0afd2b1 100644 --- a/minifirewall/tasks/config.yml +++ b/minifirewall/tasks/config.yml @@ -9,11 +9,12 @@ - name: Stat minifirewall config file (before) stat: - path: "{{ minifirewall_main_file }}" + path: "/etc/default/minifirewall" register: minifirewall_before - name: Check if minifirewall is running - shell: /sbin/iptables -L -n | grep -E "^(DROP\s+udp|ACCEPT\s+icmp)\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$" + shell: + cmd: /sbin/iptables -L -n | grep -E "^(DROP\s+udp|ACCEPT\s+icmp)\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$" changed_when: False failed_when: False check_mode: no @@ -25,14 +26,14 @@ - name: Begin marker for IP addresses lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "# BEGIN ANSIBLE MANAGED BLOCK FOR IPS" insertbefore: '^# Main interface' create: no - name: End marker for IP addresses lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" create: no line: "# END ANSIBLE MANAGED BLOCK FOR IPS" insertafter: '^PRIVILEGIEDIPS=' @@ -43,12 +44,16 @@ msg: You must provide at least 1 trusted IP - debug: - msg: "Warning: minifirewall_trusted_ips='0.0.0.0/0', the firewall is useless!" - when: minifirewall_trusted_ips == ["0.0.0.0/0"] + msg: "Warning: minifirewall_trusted_ips contains '0.0.0.0/0', the firewall is useless on IPv4!" + when: "'0.0.0.0/0' in minifirewall_trusted_ips" + +- debug: + msg: "Warning: minifirewall_trusted_ips contains '::/0', the firewall is useless on IPv6!" + when: "'::/0' in minifirewall_trusted_ips" - name: Configure IP addresses blockinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" marker: "# {mark} ANSIBLE MANAGED BLOCK FOR IPS" block: | # Main interface @@ -60,8 +65,12 @@ # Docker Mode # Changes the behaviour of minifirewall to not break the containers' network # For instance, turning it on will disable nat table purge - # Also, we'll add the DOCKER-USER chain, in iptable - DOCKER='{{ minifirewall_docker }}' + # Also, we'll add the DOCKER-USER chain, in iptables + # + # WARNING : If the port mapping is different between the host and the container + # (ie: Listen on :8090 on host, but :8080 in container) + # then you need to give the port used inside the container + DOCKER='off' # Trusted IPv4 local network # ...will be often IP/32 if you don't trust anything @@ -78,21 +87,21 @@ - name: Begin marker for ports lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "# BEGIN ANSIBLE MANAGED BLOCK FOR PORTS" insertbefore: '^# Protected services' create: no - name: End marker for ports lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "# END ANSIBLE MANAGED BLOCK FOR PORTS" insertafter: '^SERVICESUDP3=' create: no - name: Configure ports blockinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" marker: "# {mark} ANSIBLE MANAGED BLOCK FOR PORTS" block: | # Protected services @@ -116,7 +125,7 @@ - name: Configure DNSSERVEURS lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "DNSSERVEURS='{{ minifirewall_dns_servers | join(' ') }}'" regexp: "DNSSERVEURS='.*'" create: no @@ -124,7 +133,7 @@ - name: Configure HTTPSITES lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "HTTPSITES='{{ minifirewall_http_sites | join(' ') }}'" regexp: "HTTPSITES='.*'" create: no @@ -132,7 +141,7 @@ - name: Configure HTTPSSITES lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "HTTPSSITES='{{ minifirewall_https_sites | join(' ') }}'" regexp: "HTTPSSITES='.*'" create: no @@ -140,7 +149,7 @@ - name: Configure FTPSITES lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "FTPSITES='{{ minifirewall_ftp_sites | join(' ') }}'" regexp: "FTPSITES='.*'" create: no @@ -148,7 +157,7 @@ - name: Configure SSHOK lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "SSHOK='{{ minifirewall_ssh_ok | join(' ') }}'" regexp: "SSHOK='.*'" create: no @@ -156,7 +165,7 @@ - name: Configure SMTPOK lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "SMTPOK='{{ minifirewall_smtp_ok | join(' ') }}'" regexp: "SMTPOK='.*'" create: no @@ -164,7 +173,7 @@ - name: Configure SMTPSECUREOK lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "SMTPSECUREOK='{{ minifirewall_smtp_secure_ok | join(' ') }}'" regexp: "SMTPSECUREOK='.*'" create: no @@ -172,29 +181,15 @@ - name: Configure NTPOK lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "NTPOK='{{ minifirewall_ntp_ok | join(' ') }}'" regexp: "NTPOK='.*'" create: no when: minifirewall_ntp_ok is not none -- name: evomaintenance - lineinfile: - dest: "{{ minifirewall_main_file }}" - line: "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s {{ item }} -m state --state ESTABLISHED,RELATED -j ACCEPT" - insertafter: "^# EvoMaintenance" - loop: "{{ evomaintenance_hosts }}" - -- name: remove minifirewall example rule for the evomaintenance - lineinfile: - dest: "{{ minifirewall_main_file }}" - regexp: '^#.*(--sport 5432).*(-s X\.X\.X\.X)' - state: absent - when: evomaintenance_hosts | length > 0 - - name: Stat minifirewall config file (after) stat: - path: "{{ minifirewall_main_file }}" + path: "/etc/default/minifirewall" register: minifirewall_after - name: restart minifirewall diff --git a/minifirewall/tasks/install.yml b/minifirewall/tasks/install.yml index 5d6438ed..e537fb6f 100644 --- a/minifirewall/tasks/install.yml +++ b/minifirewall/tasks/install.yml @@ -6,18 +6,26 @@ state: present - name: init script is copied - template: - src: minifirewall.j2 + copy: + src: minifirewall dest: /etc/init.d/minifirewall force: "{{ minifirewall_force_upgrade_script | default('no') }}" mode: "0700" owner: root group: root +- name: include directory is present + file: + path: /etc/minifirewall.d/ + state: directory + owner: root + group: root + mode: "0700" + - name: configuration is copied copy: src: minifirewall.conf - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" force: "{{ minifirewall_force_upgrade_config | default('no') }}" mode: "0600" owner: root diff --git a/minifirewall/tasks/main.yml b/minifirewall/tasks/main.yml index 2a053d4f..5f442eb1 100644 --- a/minifirewall/tasks/main.yml +++ b/minifirewall/tasks/main.yml @@ -4,9 +4,15 @@ set_fact: minifirewall_restart_handler_name: "{{ minifirewall_restart_if_needed | bool | ternary('restart minifirewall', 'restart minifirewall (noop)') }}" +- name: Fail if minifirewall_main_file is defined + fail: + msg: "Variable minifirewall_main_file is deprecated and not configurable anymore." + when: minifirewall_main_file is defined + - include: install.yml - include: config.yml + when: minifirewall_update_config | bool - include: nrpe.yml diff --git a/minifirewall/tasks/tail.yml b/minifirewall/tasks/tail.yml index c8c4440e..199b4c7a 100644 --- a/minifirewall/tasks/tail.yml +++ b/minifirewall/tasks/tail.yml @@ -2,7 +2,7 @@ - name: Add some rules at the end of minifirewall file template: src: "{{ item }}" - dest: "{{ minifirewall_tail_file }}" + dest: "/etc/minifirewall.d/{{ minifirewall_tail_file }}" force: "{{ minifirewall_tail_force | bool }}" loop: "{{ query('first_found', templates) }}" vars: @@ -17,18 +17,6 @@ var: minifirewall_tail_template verbosity: 1 -- name: source minifirewall.tail at the end of the main file - blockinfile: - dest: "{{ minifirewall_main_file }}" - marker: "# {mark} ANSIBLE MANAGED EXTERNAL RULES" - block: ". {{ minifirewall_tail_file }}" - insertbefore: EOF - register: minifirewall_tail_source - -- debug: - var: minifirewall_tail_source - verbosity: 1 - - name: restart minifirewall # service: # name: minifirewall diff --git a/minifirewall/templates/minifirewall.j2 b/minifirewall/templates/minifirewall.j2 deleted file mode 100755 index 13b5130d..00000000 --- a/minifirewall/templates/minifirewall.j2 +++ /dev/null @@ -1,492 +0,0 @@ -#!/bin/sh - -# minifirewall is shellscripts for easy firewalling on a standalone server -# we used netfilter/iptables http://netfilter.org/ designed for recent Linux kernel -# See https://gitea.evolix.org/evolix/minifirewall - -# Copyright (c) 2007-2020 Evolix -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 3 -# of the License. - -# Description -# script for standalone server - -# Start or stop minifirewall -# - -### BEGIN INIT INFO -# Provides: minfirewall -# Required-Start: -# Required-Stop: -# Should-Start: $network $syslog $named -# Should-Stop: $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: start and stop the firewall -# Description: Firewall designed for standalone server -### END INIT INFO - -DESC="minifirewall" -NAME="minifirewall" - - -# Variables configuration -######################### - -# iptables paths -IPT=/sbin/iptables -IPT6=/sbin/ip6tables - -# TCP/IP variables -LOOPBACK='127.0.0.0/8' -CLASSA='10.0.0.0/8' -CLASSB='172.16.0.0/12' -CLASSC='192.168.0.0/16' -CLASSD='224.0.0.0/4' -CLASSE='240.0.0.0/5' -ALL='0.0.0.0' -BROAD='255.255.255.255' -PORTSROOT='0:1023' -PORTSUSER='1024:65535' - -chain_exists() -{ - local chain_name="$1" ; shift - [ $# -eq 1 ] && local intable="--table $1" - iptables $intable -nL "$chain_name" >/dev/null 2>&1 -} - -# Configuration -oldconfigfile="/etc/firewall.rc" -configfile="{{ minifirewall_main_file }}" - -IPV6=$(grep "IPV6=" {{ minifirewall_main_file }} | awk -F '=' -F "'" '{print $2}') -DOCKER=$(grep "DOCKER=" {{ minifirewall_main_file }} | awk -F '=' -F "'" '{print $2}') -INT=$(grep "INT=" {{ minifirewall_main_file }} | awk -F '=' -F "'" '{print $2}') - -case "$1" in - start) - - echo "Start IPTables rules..." - -# Stop and warn if error! -set -e -trap 'echo "ERROR in minifirewall configuration (fix it now!) or script manipulation (fix yourself)." ' INT TERM EXIT - - -# sysctl network security settings -################################## - -# Don't answer to broadcast pings -echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts - -# Ignore bogus ICMP responses -echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses - -# Disable Source Routing -for i in /proc/sys/net/ipv4/conf/*/accept_source_route; do -echo 0 > $i -done - -# Enable TCP SYN cookies to avoid TCP-SYN-FLOOD attacks -# cf http://cr.yp.to/syncookies.html -echo 1 > /proc/sys/net/ipv4/tcp_syncookies - -# Disable ICMP redirects -for i in /proc/sys/net/ipv4/conf/*/accept_redirects; do -echo 0 > $i -done - -for i in /proc/sys/net/ipv4/conf/*/send_redirects; do -echo 0 > $i -done - -# Enable Reverse Path filtering : verify if responses use same network interface -for i in /proc/sys/net/ipv4/conf/*/rp_filter; do -echo 1 > $i -done - -# log des paquets avec adresse incoherente -for i in /proc/sys/net/ipv4/conf/*/log_martians; do -echo 1 > $i -done - -# IPTables configuration -######################## - -$IPT -N LOG_DROP -$IPT -A LOG_DROP -j LOG --log-prefix '[IPTABLES DROP] : ' -$IPT -A LOG_DROP -j DROP -$IPT -N LOG_ACCEPT -$IPT -A LOG_ACCEPT -j LOG --log-prefix '[IPTABLES ACCEPT] : ' -$IPT -A LOG_ACCEPT -j ACCEPT - -if test -f $oldconfigfile; then - echo "$oldconfigfile is deprecated, rename to $configfile" >&2 - exit 1 -fi - -if ! test -f $configfile; then - echo "$configfile does not exist" >&2 - exit 1 -fi - -tmpfile=`mktemp` -. $configfile 2>$tmpfile >&2 -if [ -s $tmpfile ]; then - echo "$configfile returns standard or error output (see below). Stopping." >&2 - cat $tmpfile - exit 1 -fi -rm $tmpfile - -# Trusted ip addresses -$IPT -N ONLYTRUSTED -$IPT -A ONLYTRUSTED -j LOG_DROP -for x in $TRUSTEDIPS - do - $IPT -I ONLYTRUSTED -s $x -j ACCEPT - done - -# Privilegied ip addresses -# (trusted ip addresses *are* privilegied) -$IPT -N ONLYPRIVILEGIED -$IPT -A ONLYPRIVILEGIED -j ONLYTRUSTED -for x in $PRIVILEGIEDIPS - do - $IPT -I ONLYPRIVILEGIED -s $x -j ACCEPT - done - -# Chain for restrictions (blacklist IPs/ranges) -$IPT -N NEEDRESTRICT - -# We allow all on loopback interface -$IPT -A INPUT -i lo -j ACCEPT -[ "$IPV6" != "off" ] && $IPT6 -A INPUT -i lo -j ACCEPT -# if OUTPUTDROP -$IPT -A OUTPUT -o lo -j ACCEPT -[ "$IPV6" != "off" ] && $IPT6 -A OUTPUT -o lo -j ACCEPT - -# We avoid "martians" packets, typical when W32/Blaster virus -# attacked windowsupdate.com and DNS was changed to 127.0.0.1 -# $IPT -t NAT -I PREROUTING -s $LOOPBACK -i ! lo -j DROP -$IPT -A INPUT -s $LOOPBACK ! -i lo -j DROP - - -if [ "$DOCKER" = "on" ]; then - - $IPT -N MINIFW-DOCKER-TRUSTED - $IPT -A MINIFW-DOCKER-TRUSTED -j DROP - - $IPT -N MINIFW-DOCKER-PRIVILEGED - $IPT -A MINIFW-DOCKER-PRIVILEGED -j MINIFW-DOCKER-TRUSTED - $IPT -A MINIFW-DOCKER-PRIVILEGED -j RETURN - - $IPT -N MINIFW-DOCKER-PUB - $IPT -A MINIFW-DOCKER-PUB -j MINIFW-DOCKER-PRIVILEGED - $IPT -A MINIFW-DOCKER-PUB -j RETURN - - # Flush DOCKER-USER if exist, create it if absent - if chain_exists 'DOCKER-USER'; then - $IPT -F DOCKER-USER - else - $IPT -N DOCKER-USER - fi; - - # Pipe new connection through MINIFW-DOCKER-PUB - $IPT -A DOCKER-USER -i $INT -m state --state NEW -j MINIFW-DOCKER-PUB - $IPT -A DOCKER-USER -j RETURN - -fi - - -# Local services restrictions -############################# - -# Allow services for $INTLAN (local server or local network) -$IPT -A INPUT -s $INTLAN -j ACCEPT - -# Enable protection chain for sensible services -for x in $SERVICESTCP1p - do - $IPT -A INPUT -p tcp --dport $x -j NEEDRESTRICT - done - -for x in $SERVICESUDP1p - do - $IPT -A INPUT -p udp --dport $x -j NEEDRESTRICT - done - -# Public service -for x in $SERVICESTCP1 - do - $IPT -A INPUT -p tcp --dport $x -j ACCEPT - [ "$IPV6" != "off" ] && $IPT6 -A INPUT -p tcp --dport $x -j ACCEPT - done - -for x in $SERVICESUDP1 - do - $IPT -A INPUT -p udp --dport $x -j ACCEPT - [ "$IPV6" != "off" ] && $IPT6 -A INPUT -p udp --dport $x -j ACCEPT - done - -# Privilegied services -for x in $SERVICESTCP2 - do - $IPT -A INPUT -p tcp --dport $x -j ONLYPRIVILEGIED - done - -for x in $SERVICESUDP2 - do - $IPT -A INPUT -p udp --dport $x -j ONLYPRIVILEGIED - done - -# Private services -for x in $SERVICESTCP3 - do - $IPT -A INPUT -p tcp --dport $x -j ONLYTRUSTED - done - -for x in $SERVICESUDP3 - do - $IPT -A INPUT -p udp --dport $x -j ONLYTRUSTED - done - - -if [ "$DOCKER" = "on" ]; then - - # Public services defined in SERVICESTCP1 & SERVICESUDP1 - for dstport in $SERVICESTCP1 - do - $IPT -I MINIFW-DOCKER-PUB -p tcp --dport "$dstport" -j RETURN - done - - for dstport in $SERVICESUDP1 - do - $IPT -I MINIFW-DOCKER-PUB -p udp --dport "$dstport" -j RETURN - done - - # Privileged services (accessible from privileged & trusted IPs) - for dstport in $SERVICESTCP2 - do - for srcip in $PRIVILEGIEDIPS - do - $IPT -I MINIFW-DOCKER-PRIVILEGED -p tcp -s "$srcip" --dport "$dstport" -j RETURN - done - - for srcip in $TRUSTEDIPS - do - $IPT -I MINIFW-DOCKER-PRIVILEGED -p tcp -s "$srcip" --dport "$dstport" -j RETURN - done - done - - for dstport in $SERVICESUDP2 - do - for srcip in $PRIVILEGIEDIPS - do - $IPT -I MINIFW-DOCKER-PRIVILEGED -p udp -s "$srcip" --dport "$dstport" -j RETURN - done - - for srcip in $TRUSTEDIPS - do - $IPT -I MINIFW-DOCKER-PRIVILEGED -p udp -s "$srcip" --dport "$dstport" -j RETURN - done - done - - # Trusted services (accessible from trusted IPs) - for dstport in $SERVICESTCP3 - do - for srcip in $TRUSTEDIPS - do - $IPT -I MINIFW-DOCKER-TRUSTED -p tcp -s "$srcip" --dport "$dstport" -j RETURN - done - done - - for dstport in $SERVICESUDP3 - do - for srcip in $TRUSTEDIPS - do - $IPT -I MINIFW-DOCKER-TRUSTED -p udp -s "$srcip" --dport "$dstport" -j RETURN - done - done -fi - -# External services -################### - -# DNS authorizations -for x in $DNSSERVEURS - do - $IPT -A INPUT -p tcp ! --syn --sport 53 --dport $PORTSUSER -s $x -j ACCEPT - $IPT -A INPUT -p udp --sport 53 --dport $PORTSUSER -s $x -m state --state ESTABLISHED,RELATED -j ACCEPT - $IPT -A OUTPUT -o $INT -p udp -d $x --dport 53 --match state --state NEW -j ACCEPT - done - -# HTTP (TCP/80) authorizations -for x in $HTTPSITES - do - $IPT -A INPUT -p tcp ! --syn --sport 80 --dport $PORTSUSER -s $x -j ACCEPT - done - -# HTTPS (TCP/443) authorizations -for x in $HTTPSSITES - do - $IPT -A INPUT -p tcp ! --syn --sport 443 --dport $PORTSUSER -s $x -j ACCEPT - done - -# FTP (so complex protocol...) authorizations -for x in $FTPSITES - do - # requests on Control connection - $IPT -A INPUT -p tcp ! --syn --sport 21 --dport $PORTSUSER -s $x -j ACCEPT - # FTP port-mode on Data Connection - $IPT -A INPUT -p tcp --sport 20 --dport $PORTSUSER -s $x -j ACCEPT - # FTP passive-mode on Data Connection - # WARNING, this allow all connections on TCP ports > 1024 - $IPT -A INPUT -p tcp ! --syn --sport $PORTSUSER --dport $PORTSUSER -s $x -j ACCEPT - done - -# SSH authorizations -for x in $SSHOK - do - $IPT -A INPUT -p tcp ! --syn --sport 22 -s $x -j ACCEPT - done - -# SMTP authorizations -for x in $SMTPOK - do - $IPT -A INPUT -p tcp ! --syn --sport 25 --dport $PORTSUSER -s $x -j ACCEPT - done - -# secure SMTP (TCP/465 et TCP/587) authorizations -for x in $SMTPSECUREOK - do - $IPT -A INPUT -p tcp ! --syn --sport 465 --dport $PORTSUSER -s $x -j ACCEPT - $IPT -A INPUT -p tcp ! --syn --sport 587 --dport $PORTSUSER -s $x -j ACCEPT - done - -# NTP authorizations -for x in $NTPOK - do - $IPT -A INPUT -p udp --sport 123 -s $x -j ACCEPT - $IPT -A OUTPUT -o $INT -p udp -d $x --dport 123 --match state --state NEW -j ACCEPT - done - -# Always allow ICMP -$IPT -A INPUT -p icmp -j ACCEPT -[ "$IPV6" != "off" ] && $IPT6 -A INPUT -p icmpv6 -j ACCEPT - - -# IPTables policy -################# - -# by default DROP INPUT packets -$IPT -P INPUT DROP -[ "$IPV6" != "off" ] && $IPT6 -P INPUT DROP - -# by default, no FORWARING (deprecated for Virtual Machines) -#echo 0 > /proc/sys/net/ipv4/ip_forward -#$IPT -P FORWARD DROP -#$IPT6 -P FORWARD DROP - -# by default allow OUTPUT packets... but drop UDP packets (see OUTPUTDROP to drop OUTPUT packets) -$IPT -P OUTPUT ACCEPT -[ "$IPV6" != "off" ] && $IPT6 -P OUTPUT ACCEPT -$IPT -A OUTPUT -o $INT -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT -$IPT -A OUTPUT -p udp --match state --state ESTABLISHED,RELATED -j ACCEPT -$IPT -A OUTPUT -p udp -j DROP -[ "$IPV6" != "off" ] && $IPT6 -A OUTPUT -o $INT -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT -[ "$IPV6" != "off" ] && $IPT6 -A OUTPUT -p udp --match state --state ESTABLISHED,RELATED -j ACCEPT -[ "$IPV6" != "off" ] && $IPT6 -A OUTPUT -p udp -j DROP - -trap - INT TERM EXIT - - echo "...starting IPTables rules is now finish : OK" - ;; - - stop) - - echo "Flush all rules and accept everything..." - - # Delete all rules - $IPT -F INPUT - $IPT -F OUTPUT - $IPT -F LOG_DROP - $IPT -F LOG_ACCEPT - $IPT -F ONLYTRUSTED - $IPT -F ONLYPRIVILEGIED - $IPT -F NEEDRESTRICT - [ "$DOCKER" = "off" ] && $IPT -t nat -F - $IPT -t mangle -F - [ "$IPV6" != "off" ] && $IPT6 -F INPUT - [ "$IPV6" != "off" ] && $IPT6 -F OUTPUT - - if [ "$DOCKER" = "on" ]; then - $IPT -F DOCKER-USER - $IPT -A DOCKER-USER -j RETURN - - $IPT -F MINIFW-DOCKER-PUB - $IPT -X MINIFW-DOCKER-PUB - $IPT -F MINIFW-DOCKER-PRIVILEGED - $IPT -X MINIFW-DOCKER-PRIVILEGED - $IPT -F MINIFW-DOCKER-TRUSTED - $IPT -X MINIFW-DOCKER-TRUSTED - - fi - - # Accept all - $IPT -P INPUT ACCEPT - $IPT -P OUTPUT ACCEPT - [ "$IPV6" != "off" ] && $IPT6 -P INPUT ACCEPT - [ "$IPV6" != "off" ] && $IPT6 -P OUTPUT ACCEPT - #$IPT -P FORWARD ACCEPT - #$IPT -t nat -P PREROUTING ACCEPT - #$IPT -t nat -P POSTROUTING ACCEPT - - # Delete non-standard chains - $IPT -X LOG_DROP - $IPT -X LOG_ACCEPT - $IPT -X ONLYPRIVILEGIED - $IPT -X ONLYTRUSTED - $IPT -X NEEDRESTRICT - - echo "...flushing IPTables rules is now finish : OK" - ;; - - status) - - $IPT -L -n -v --line-numbers - $IPT -t nat -L -n -v --line-numbers - $IPT -t mangle -L -n -v --line-numbers - $IPT6 -L -n -v --line-numbers - $IPT6 -t mangle -L -n -v --line-numbers - ;; - - reset) - - echo "Reset all IPTables counters..." - - $IPT -Z - $IPT -t nat -Z - $IPT -t mangle -Z - [ "$IPV6" != "off" ] && $IPT6 -Z - [ "$IPV6" != "off" ] && $IPT6 -t mangle -Z - - echo "...reseting IPTables counters is now finish : OK" - ;; - - restart) - - $0 stop - $0 start - ;; - - *) - - echo "Usage: $0 {start|stop|restart|status|reset|squid}" - exit 1 -esac - -exit 0