diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b6bb7f8..70e058ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * etc-git: use "ansible-commit" to efficiently commit all available repositories (including /etc inside LXC) from Ansible * minifirewall: configure proxy/backup/sysctl values +* minifirewall: compatibility with "legacy" version of minifirewall * nagios-nrpe: Add a check dhcp_pool * redis : Activate overcommit sysctl * munin: Add possibility to install local plugins, and install dhcp_pool plugin diff --git a/minifirewall/defaults/main.yml b/minifirewall/defaults/main.yml index 4c084154..18d7d5b3 100644 --- a/minifirewall/defaults/main.yml +++ b/minifirewall/defaults/main.yml @@ -1,9 +1,14 @@ --- -# Deprecated variable -# minifirewall_main_file: /etc/default/minifirewall +# possible values: Null (default), modern or legacy +minifirewall_install_mode: Null -minifirewall_tail_file: zzz-tail +# BEGIN legacy variables +minifirewall_legacy_main_file: /etc/default/minifirewall +minifirewall_legacy_tail_file: /etc/default/minifirewall.tail +# END legacy variabes + +minifirewall_tail_file: /etc/minifirewall.d/zzz-tail minifirewall_tail_included: False minifirewall_tail_force: True @@ -14,17 +19,17 @@ 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 }}" minifirewall_ipv6: "on" minifirewall_intlan: "{{ ansible_default_ipv4.address }}/32" minifirewall_docker: "off" minifirewall_default_trusted_ips: [] +minifirewall_legacy_fallback_trusted_ips: ['0.0.0.0/0'] +minifirewall_fallback_trusted_ips: ['0.0.0.0/0', '::/0'] minifirewall_additional_trusted_ips: [] # and default to ['0.0.0.0/0', '::/0'] if the result is still empty -minifirewall_trusted_ips: "{{ minifirewall_default_trusted_ips | union(minifirewall_additional_trusted_ips) | unique | default(['0.0.0.0/0', '::/0'], true) }}" +minifirewall_trusted_ips: "{{ minifirewall_default_trusted_ips | union(minifirewall_additional_trusted_ips) | unique }}" minifirewall_privilegied_ips: [] minifirewall_protected_ports_tcp: [22] diff --git a/minifirewall/files/minifirewall.legacy.conf b/minifirewall/files/minifirewall.legacy.conf new file mode 100644 index 00000000..47be78bf --- /dev/null +++ b/minifirewall/files/minifirewall.legacy.conf @@ -0,0 +1,106 @@ +# Configuration for minifirewall : https://gitea.evolix.org/evolix/minifirewall +# Version 20.12 — 2020-12-01 22:55:35 + +# Main interface +INT='eth0' + +# IPv6 +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 +DOCKER='off' + +# Trusted IPv4 local network +# ...will be often IP/32 if you don't trust anything +INTLAN='192.168.0.2/32' + +# 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' + +# Privilegied IPv4 addresses for semi-public services +# (no need to add again TRUSTEDIPS) +PRIVILEGIEDIPS='' + + +# Local services IPv4/IPv6 restrictions +####################################### + +# Protected services +# (add also in Public services if needed) +SERVICESTCP1p='22222' +SERVICESUDP1p='' + +# Public services (IPv4/IPv6) +SERVICESTCP1='22222' +SERVICESUDP1='' + +# Semi-public services (IPv4) +SERVICESTCP2='22' +SERVICESUDP2='' + +# Private services (IPv4) +SERVICESTCP3='5666' +SERVICESUDP3='' + +# Standard output IPv4 access restrictions +########################################## + +# DNS authorizations +# (if you have local DNS server, set 0.0.0.0/0) +DNSSERVEURS='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' + +# HTTPS authorizations +HTTPSSITES='0.0.0.0/0' + +# FTP authorizations +FTPSITES='' + +# SSH authorizations +SSHOK='0.0.0.0/0' + +# SMTP authorizations +SMTPOK='0.0.0.0/0' + +# SMTP secure authorizations (ports TCP/465 and TCP/587) +SMTPSECUREOK='' + +# NTP authorizations +NTPOK='0.0.0.0/0' + + +# IPv6 Specific rules +##################### + +# 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 + +# 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 + +# 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 + +# IPv4 Specific rules +##################### + +# /sbin/iptables ... diff --git a/minifirewall/tasks/config.legacy.yml b/minifirewall/tasks/config.legacy.yml new file mode 100644 index 00000000..8a7f5990 --- /dev/null +++ b/minifirewall/tasks/config.legacy.yml @@ -0,0 +1,218 @@ +--- + +- debug: + var: minifirewall_trusted_ips + verbosity: 1 +- debug: + var: minifirewall_privilegied_ips + verbosity: 1 + +- name: Stat minifirewall config file (before) + stat: + path: "{{ minifirewall_main_file }}" + 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*$" + changed_when: False + failed_when: False + check_mode: no + register: minifirewall_is_running + +- debug: + var: minifirewall_is_running + verbosity: 1 + +- name: Begin marker for IP addresses + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "# BEGIN ANSIBLE MANAGED BLOCK FOR IPS" + insertbefore: '^# Main interface' + create: no + +- name: End marker for IP addresses + lineinfile: + dest: "{{ minifirewall_main_file }}" + create: no + line: "# END ANSIBLE MANAGED BLOCK FOR IPS" + insertafter: '^PRIVILEGIEDIPS=' + +- name: Verify that at least 1 trusted IP is provided + assert: + that: minifirewall_trusted_ips | length > 0 + 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"] + +- name: Configure IP addresses + blockinfile: + dest: "{{ minifirewall_main_file }}" + marker: "# {mark} ANSIBLE MANAGED BLOCK FOR IPS" + block: | + # Main interface + INT='{{ minifirewall_int }}' + + # IPv6 + IPV6='{{ minifirewall_ipv6 }}' + + # 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 }}' + + # Trusted IPv4 local network + # ...will be often IP/32 if you don't trust anything + INTLAN='{{ minifirewall_intlan }}' + + # Trusted IPv4 addresses for private and semi-public services + TRUSTEDIPS='{{ minifirewall_trusted_ips | join(' ') }}' + + # Privilegied IPv4 addresses for semi-public services + # (no need to add again TRUSTEDIPS) + PRIVILEGIEDIPS='{{ minifirewall_privilegied_ips | join(' ') }}' + create: no + register: minifirewall_config_ips + +- name: Begin marker for ports + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "# BEGIN ANSIBLE MANAGED BLOCK FOR PORTS" + insertbefore: '^# Protected services' + create: no + +- name: End marker for ports + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "# END ANSIBLE MANAGED BLOCK FOR PORTS" + insertafter: '^SERVICESUDP3=' + create: no + +- name: Configure ports + blockinfile: + dest: "{{ minifirewall_main_file }}" + marker: "# {mark} ANSIBLE MANAGED BLOCK FOR PORTS" + block: | + # Protected services + # (add also in Public services if needed) + SERVICESTCP1p='{{ minifirewall_protected_ports_tcp | join(' ') }}' + SERVICESUDP1p='{{ minifirewall_protected_ports_udp | join(' ') }}' + + # Public services (IPv4/IPv6) + SERVICESTCP1='{{ minifirewall_public_ports_tcp | join(' ') }}' + SERVICESUDP1='{{ minifirewall_public_ports_udp | join(' ') }}' + + # Semi-public services (IPv4) + SERVICESTCP2='{{ minifirewall_semipublic_ports_tcp | join(' ') }}' + SERVICESUDP2='{{ minifirewall_semipublic_ports_udp | join(' ') }}' + + # Private services (IPv4) + SERVICESTCP3='{{ minifirewall_private_ports_tcp | join(' ') }}' + SERVICESUDP3='{{ minifirewall_private_ports_udp | join(' ') }}' + create: no + register: minifirewall_config_ports + +- name: Configure DNSSERVEURS + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "DNSSERVEURS='{{ minifirewall_dns_servers | join(' ') }}'" + regexp: "DNSSERVEURS='.*'" + create: no + when: minifirewall_dns_servers is not none + +- name: Configure HTTPSITES + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "HTTPSITES='{{ minifirewall_http_sites | join(' ') }}'" + regexp: "HTTPSITES='.*'" + create: no + when: minifirewall_http_sites is not none + +- name: Configure HTTPSSITES + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "HTTPSSITES='{{ minifirewall_https_sites | join(' ') }}'" + regexp: "HTTPSSITES='.*'" + create: no + when: minifirewall_https_sites is not none + +- name: Configure FTPSITES + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "FTPSITES='{{ minifirewall_ftp_sites | join(' ') }}'" + regexp: "FTPSITES='.*'" + create: no + when: minifirewall_ftp_sites is not none + +- name: Configure SSHOK + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "SSHOK='{{ minifirewall_ssh_ok | join(' ') }}'" + regexp: "SSHOK='.*'" + create: no + when: minifirewall_ssh_ok is not none + +- name: Configure SMTPOK + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "SMTPOK='{{ minifirewall_smtp_ok | join(' ') }}'" + regexp: "SMTPOK='.*'" + create: no + when: minifirewall_smtp_ok is not none + +- name: Configure SMTPSECUREOK + lineinfile: + dest: "{{ minifirewall_main_file }}" + line: "SMTPSECUREOK='{{ minifirewall_smtp_secure_ok | join(' ') }}'" + regexp: "SMTPSECUREOK='.*'" + create: no + when: minifirewall_smtp_secure_ok is not none + +- name: Configure NTPOK + lineinfile: + dest: "{{ minifirewall_main_file }}" + 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 }}" + register: minifirewall_after + +- name: restart minifirewall + command: /etc/init.d/minifirewall restart + register: minifirewall_init_restart + failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" + when: + - minifirewall_restart_if_needed | bool + - minifirewall_is_running.rc == 0 + - minifirewall_before.stat.checksum != minifirewall_after.stat.checksum + +- name: restart minifirewall (noop) + meta: noop + register: minifirewall_init_restart + failed_when: False + changed_when: False + when: not (minifirewall_restart_if_needed | bool) + +- debug: + var: minifirewall_init_restart + verbosity: 2 diff --git a/minifirewall/tasks/install.legacy.yml b/minifirewall/tasks/install.legacy.yml new file mode 100644 index 00000000..323426b5 --- /dev/null +++ b/minifirewall/tasks/install.legacy.yml @@ -0,0 +1,24 @@ +--- + +- name: dependencies are satisfied + apt: + name: iptables + state: present + +- name: init script is copied + template: + src: minifirewall.legacy.j2 + dest: /etc/init.d/minifirewall + force: "{{ minifirewall_force_upgrade_script | default('no') }}" + mode: "0700" + owner: root + group: root + +- name: configuration is copied + copy: + src: minifirewall.legacy.conf + dest: "{{ minifirewall_main_file }}" + force: "{{ minifirewall_force_upgrade_config | default('no') }}" + mode: "0600" + owner: root + group: root diff --git a/minifirewall/tasks/install.yml b/minifirewall/tasks/install.yml index 9c0483b9..daac6f81 100644 --- a/minifirewall/tasks/install.yml +++ b/minifirewall/tasks/install.yml @@ -41,23 +41,3 @@ mode: "0600" owner: root group: root - -- include_role: - name: evolix/remount-usr - -- name: /usr/share/scripts exists - file: - dest: /usr/share/scripts - mode: "0700" - owner: root - group: root - state: directory - -- name: blacklist-countries.sh is copied - copy: - src: blacklist-countries.sh - dest: /usr/share/scripts/blacklist-countries.sh - force: "no" - mode: "0700" - owner: root - group: root diff --git a/minifirewall/tasks/main.yml b/minifirewall/tasks/main.yml index 0fbb3ad6..e8355ceb 100644 --- a/minifirewall/tasks/main.yml +++ b/minifirewall/tasks/main.yml @@ -4,25 +4,107 @@ 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 +# Legacy or modern mode? ############################################## + +- name: Check minifirewall + stat: + path: /etc/init.d/minifirewall + register: _minifirewall_check + +# Legacy versions of minifirewall don't define the VERSION variable +- name: Look for minifirewall version + shell: "grep -E '^\\s*VERSION=' /etc/init.d/minifirewall" + failed_when: False + changed_when: False + check_mode: False + register: _minifirewall_version_check + +- name: Set install mode to legacy if needed + set_fact: + minifirewall_install_mode: legacy + minifirewall_main_file: "{{ minifirewall_legacy_main_file }}" + minifirewall_tail_file: "{{ minifirewall_legacy_tail_file }}" + when: + - minifirewall_install_mode != 'modern' + - not (minifirewall_force_upgrade_script | bool) + - _minifirewall_version_check.rc == 1 # grep didn't find but the file exists + +- name: Set install mode to modern if not legacy + set_fact: + minifirewall_install_mode: modern + when: minifirewall_install_mode != 'legacy' + +- name: Debug install mode + debug: + var: minifirewall_install_mode + verbosity: 1 + +####################################################################### + +- name: Fail if minifirewall_main_file is defined (legacy mode) fail: msg: "Variable minifirewall_main_file is deprecated and not configurable anymore." - when: minifirewall_main_file is defined + when: + - minifirewall_install_mode != 'legacy' + - minifirewall_main_file is defined -- include: install.yml +- name: Install tasks (modern mode) + include: install.yml + when: minifirewall_install_mode != 'legacy' -- include: config.yml - when: minifirewall_update_config | bool +- name: Install tasks (legacy mode) + include: install.legacy.yml + when: minifirewall_install_mode == 'legacy' -- include: nrpe.yml +- name: Config tasks (modern mode) + include: config.yml + when: + - minifirewall_install_mode != 'legacy' + - minifirewall_update_config | bool -- include: activate.yml +- name: Config tasks (legacy mode) + include: config.legacy.yml + when: + - minifirewall_install_mode == 'legacy' + - minifirewall_update_config | bool -- include: tail.yml - when: minifirewall_tail_included | bool +- name: Utils tasks + include: utils.yml -- name: Force restart minifirewall +- name: NRPE tasks + include: nrpe.yml + +- name: Activation tasks + include: activate.yml + +- name: Tail tasks (modern mode) + include: tail.yml + when: + - minifirewall_install_mode != 'legacy' + - minifirewall_tail_included | bool + +- name: Tail tasks (legacy mode) + include: tail.legacy.yml + when: + - minifirewall_install_mode == 'legacy' + - minifirewall_tail_included | bool + +# Restart? + +- name: Force restart minifirewall (modern mode) command: /etc/init.d/minifirewall restart register: minifirewall_init_restart failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" - when: minifirewall_restart_force | bool \ No newline at end of file + changed_when: "'starting IPTables rules is now finish : OK' in minifirewall_init_restart.stdout" + when: + - minifirewall_install_mode != 'legacy' + - minifirewall_restart_force | bool + +- name: Force restart minifirewall (legacy mode) + command: /etc/init.d/minifirewall restart + register: minifirewall_init_restart + failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" + changed_when: "'starting IPTables rules is now finish : OK' in minifirewall_init_restart.stdout" + when: + - minifirewall_install_mode == 'legacy' + - minifirewall_restart_force | bool \ No newline at end of file diff --git a/minifirewall/tasks/tail.legacy.yml b/minifirewall/tasks/tail.legacy.yml new file mode 100644 index 00000000..7a13eefa --- /dev/null +++ b/minifirewall/tasks/tail.legacy.yml @@ -0,0 +1,50 @@ +--- +- name: Add some rules at the end of minifirewall file + template: + src: "{{ item }}" + dest: "{{ minifirewall_tail_file }}" + force: "{{ minifirewall_tail_force | bool }}" + follow: yes + loop: "{{ query('first_found', templates) }}" + vars: + templates: + - "templates/minifirewall-tail/minifirewall.{{ inventory_hostname }}.tail.j2" + - "templates/minifirewall-tail/minifirewall.{{ host_group | default('all') }}.tail.j2" + - "templates/minifirewall-tail/minifirewall.default.tail.j2" + - "templates/minifirewall.default.tail.j2" + register: minifirewall_tail_template + +- debug: + 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 + command: /etc/init.d/minifirewall restart + register: minifirewall_init_restart + failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" + when: + - minifirewall_tail_template is changed + - minifirewall_restart_if_needed | bool + +- name: restart minifirewall (noop) + meta: noop + register: minifirewall_init_restart + failed_when: False + changed_when: False + when: not (minifirewall_restart_if_needed | bool) + +- debug: + var: minifirewall_init_restart + verbosity: 1 diff --git a/minifirewall/tasks/tail.yml b/minifirewall/tasks/tail.yml index a1bfba64..ae771017 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: "/etc/minifirewall.d/{{ minifirewall_tail_file }}" + dest: "{{ minifirewall_tail_file }}" force: "{{ minifirewall_tail_force | bool }}" follow: yes loop: "{{ query('first_found', templates) }}" @@ -19,9 +19,6 @@ verbosity: 1 - name: restart minifirewall - # service: - # name: minifirewall - # state: restarted command: /etc/init.d/minifirewall restart register: minifirewall_init_restart failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" diff --git a/minifirewall/tasks/utils.yml b/minifirewall/tasks/utils.yml new file mode 100644 index 00000000..775bdd95 --- /dev/null +++ b/minifirewall/tasks/utils.yml @@ -0,0 +1,21 @@ +--- + +- include_role: + name: evolix/remount-usr + +- name: /usr/share/scripts exists + file: + dest: /usr/share/scripts + mode: "0700" + owner: root + group: root + state: directory + +- name: blacklist-countries.sh is copied + copy: + src: blacklist-countries.sh + dest: /usr/share/scripts/blacklist-countries.sh + force: "no" + mode: "0700" + owner: root + group: root \ No newline at end of file diff --git a/minifirewall/templates/minifirewall.legacy.j2 b/minifirewall/templates/minifirewall.legacy.j2 new file mode 100644 index 00000000..13b5130d --- /dev/null +++ b/minifirewall/templates/minifirewall.legacy.j2 @@ -0,0 +1,492 @@ +#!/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 diff --git a/squid/defaults/main.yml b/squid/defaults/main.yml index 2188d606..8cbf43d4 100644 --- a/squid/defaults/main.yml +++ b/squid/defaults/main.yml @@ -7,4 +7,3 @@ squid_whitelist_items: [] squid_localproxy_enable: False -minifirewall_main_file: /etc/default/minifirewall diff --git a/squid/tasks/minifirewall.legacy.yml b/squid/tasks/minifirewall.legacy.yml new file mode 100644 index 00000000..f7e78ee5 --- /dev/null +++ b/squid/tasks/minifirewall.legacy.yml @@ -0,0 +1,43 @@ +--- +- name: Check if Minifirewall is present + stat: + path: "/etc/default/minifirewall" + check_mode: no + register: minifirewall_test + +- block: + - name: HTTPSITES list is commented in minifirewall + replace: + dest: "/etc/default/minifirewall" + regexp: "^(HTTPSITES='[^0-9])" + replace: '#\1' + notify: restart minifirewall + + - name: all HTTPSITES are authorized in minifirewall + lineinfile: + dest: "/etc/default/minifirewall" + line: "HTTPSITES='0.0.0.0/0'" + regexp: "HTTPSITES='.*'" + insertafter: "^#HTTPSITES=" + notify: restart minifirewall + + - name: add iptables rules for the proxy + lineinfile: + dest: "/etc/default/minifirewall" + regexp: "^#? *{{ item }}" + line: "{{ item }}" + insertafter: "^# Proxy" + loop: + - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" + - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d {{ squid_address }} -j ACCEPT" + - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.0/8 -j ACCEPT" + - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8888" + notify: restart minifirewall + + - name: remove minifirewall example rule for the proxy + lineinfile: + dest: "/etc/default/minifirewall" + regexp: '^#.*(-t nat).*(-d X\.X\.X\.X)' + state: absent + notify: restart minifirewall + when: minifirewall_test.stat.exists diff --git a/squid/tasks/minifirewall.yml b/squid/tasks/minifirewall.yml index e878b0a8..5abdf9df 100644 --- a/squid/tasks/minifirewall.yml +++ b/squid/tasks/minifirewall.yml @@ -1,29 +1,37 @@ --- - name: Check if Minifirewall is present stat: - path: "{{ minifirewall_main_file }}" + path: "/etc/default/minifirewall" check_mode: no register: minifirewall_test - block: - name: HTTPSITES list is commented in minifirewall replace: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" regexp: "^(HTTPSITES='[^0-9])" replace: '#\1' notify: restart minifirewall - name: all HTTPSITES are authorized in minifirewall lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" line: "HTTPSITES='0.0.0.0/0'" regexp: "HTTPSITES='.*'" insertafter: "^#HTTPSITES=" notify: restart minifirewall - - name: add iptables rules for the proxy + # The PROXY variable means that minifirewall is "modern" + - name: Look for PROXY variable + shell: "grep -E '^\\s*PROXY=' /etc/default/minifirewall" + failed_when: False + changed_when: False + check_mode: False + register: _minifirewall_proxy_var_check + + - name: Set proxy configuration for minifirewall (legacy mode) lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" regexp: "^#? *{{ item }}" line: "{{ item }}" insertafter: "^# Proxy" @@ -33,11 +41,21 @@ - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.0/8 -j ACCEPT" - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8888" notify: restart minifirewall + when: _minifirewall_proxy_var_check.rc == 1 - - name: remove minifirewall example rule for the proxy + - name: remove minifirewall example rule for the proxy (legacy mode) lineinfile: - dest: "{{ minifirewall_main_file }}" + dest: "/etc/default/minifirewall" regexp: '^#.*(-t nat).*(-d X\.X\.X\.X)' state: absent notify: restart minifirewall + when: _minifirewall_proxy_var_check.rc == 1 + + - name: Set proxy configuration for minifirewall (modern mode) + replace: + dest: "/etc/default/minifirewall" + replace: "PROXY='on'" + regexp: "PROXY='.*'" + notify: restart minifirewall + when: _minifirewall_proxy_var_check.rc == 0 when: minifirewall_test.stat.exists