Besoin d'avis pour des règles pare-feu par défaut

Tags: #<Tag:0x00007feb9c89e128>

Hello,

Je souhaite attribuer à mes VMs des règles firewall attribuées par défaut. Ensuite, en fonction des services que je mettrai derrière, je les modifierai sensiblement (du DNS, MAIL, FTP, HTTPS à venir, mais logiquement même en l’état, ça ne devrait pas bloquer).
N’étant pas très à l’aise avec iptables, je souhaiterais votre avis là-dessus, pour voir si quelque-chose m’a échappé, si il y a des incohérences ou si il est possible de le simplifier.

Je l’ai voulu assez ouvert, mais bloquant les attaques les plus basiques. Pour tout ce qui est bruteforce et autres lourdeurs, je laisse la main à Fail2ban, dont j’activerai les règles progressivement.

Petite précision : debian 10 + utilisation de fail2ban (avec les règles SSH légèrement modifiées)

#!/bin/sh

# Internet
IFACE_INET=ens3

# Tout accepter
iptables -t filter -P INPUT ACCEPT
iptables -t filter -P FORWARD ACCEPT
iptables -t filter -P OUTPUT ACCEPT
iptables -t nat -P PREROUTING ACCEPT
iptables -t nat -P POSTROUTING ACCEPT
iptables -t nat -P OUTPUT ACCEPT
iptables -t mangle -P PREROUTING ACCEPT
iptables -t mangle -P INPUT ACCEPT
iptables -t mangle -P FORWARD ACCEPT
iptables -t mangle -P OUTPUT ACCEPT
iptables -t mangle -P POSTROUTING ACCEPT

# Remettre les compteurs à zéro
iptables -t filter -Z
iptables -t nat -Z
iptables -t mangle -Z

# Supprimer toutes les règles actives et les chaînes personnalisées
iptables -t filter -F
iptables -t filter -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

# Politique par défaut
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Faire confiance à nous-mêmes
iptables -A INPUT -i lo -j ACCEPT

# Connexions établies
iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT

# SSH illimité
iptables -A INPUT -p tcp --dport 2278 -s ip1,ip2 -j ACCEPT
iptables -A INPUT -p tcp --dport 2278 -j DROP

# Blocage de paquets invalides
iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROP

# Bloque tous les nouveaux paquets n'ayant pas le SYN Flag
iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP

# TCP MSS mal formé
iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

# Bloque tous les paquets TCP avec un flag inhabituel
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,FIN FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL ALL -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

# Bloque les paquets des subnets privés
iptables -t mangle -A PREROUTING -s 224.0.0.0/3 -j DROP
iptables -t mangle -A PREROUTING -s 169.254.0.0/16 -j DROP
iptables -t mangle -A PREROUTING -s 172.16.0.0/12 -j DROP
iptables -t mangle -A PREROUTING -s 192.0.2.0/24 -j DROP
iptables -t mangle -A PREROUTING -s 192.168.0.0/16 -j DROP
iptables -t mangle -A PREROUTING -s 10.0.0.0/8 -j DROP
iptables -t mangle -A PREROUTING -s 0.0.0.0/8 -j DROP
iptables -t mangle -A PREROUTING -s 240.0.0.0/5 -j DROP
iptables -t mangle -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP

# Rejet du ping
iptables -t mangle -A PREROUTING -p icmp -j DROP

# Trop de connexions pour une même hote
iptables -A INPUT -p tcp -m connlimit --connlimit-above 80 -j REJECT --reject-with tcp-reset

# Nombre de connexion TCP max/s pour une hote
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP

# Anti scan de port
iptables -N port-scanning
iptables -A port-scanning -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 2 -j RETURN
iptables -A port-scanning -j DROP

# Enregistrer les connexions refusées
iptables -A INPUT -m limit --limit 2/min -j LOG \
  --log-prefix "Packets DROP"
iptables -A INPUT -j DROP

# On relance Fail2ban
/usr/sbin/service fail2ban restart

Je virerai peut-être la règle port-scanning, je pense qu’avec des clients mails un peu bogués ou mal configurés, cela pourra peut-être poser problème avec un serveur de mail.
Idem pour le rejet du ping, dans certains cas c’est plutôt utile.

Bonjour,
Euh, si j’ai bien compris, IPtables est remplacé par NFtables sous Buster. Je crois qu’il est déconseillée d’utiliser encore IPtables, toujours si j’ai bien compris :slight_smile:

ok, j’ai juste à virer les occurrences “iptables” dans mon script, car si j’ai bien compris, nftables utilise la même syntaxe (c’était à priori vrai en janvier).

salut
l’exemple de conf pour PC fourni par Debian

/usr/share/doc/nftables/examples/workstation.nft

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
	chain input {
		type filter hook input priority 0;

		# accept any localhost traffic
		iif lo accept

		# accept traffic originated from us
		ct state established,related accept

		# activate the following line to accept common local services
		#tcp dport { 22, 80, 443 } ct state new accept

		# accept neighbour discovery otherwise IPv6 connectivity breaks.
		ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit,  nd-router-advert, nd-neighbor-advert } accept

		# count and drop any other traffic
		counter drop
	}
}

ça drop bien

root@debian:~# nft list ruleset
table inet filter {
	chain input {
		type filter hook input priority filter; policy accept;
		iif "lo" accept
		ct state established,related accept
		tcp dport { 80, 443, 8200 } ct state new accept
		counter packets 1051 bytes 466385 drop
	}
}
root@debian:~# 

Pas du tout. La syntaxe de nftables est totalement différente de celle d’iptables.
Dans le paquet iptables de buster, il y a deux variantes de la commande iptables :

  • une qui utilise l’infrastructure iptables du noyau

  • une qui traduit les règles iptables en règles nftables et utilise l’infrastructure nftables du noyau.

Par défaut, iptables pointe vers la seconde. A noter que certaines règles ne peuvent être traduites et provoqueront une erreur.

Attention à vérifier si fail2ban utilise iptables ou nftables.

Quelques commentaires sur le script :

# TCP MSS mal formé
iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

En quoi une valeur de MSS inférieure à 536 est-elle mal formée ?
Et pourquoi rejeter une telle valeur de MSS dans les connexions entrantes (NEW) et pas dans les réponses aux connexions sortantes ?

Note : la table mangle n’est pas destinée à faire du filtrage.

iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP

Redondant puisque ALL = FIN,SYN,RST,PSH,ACK,URG

iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,FIN FIN -j DROP

Redondant.

iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

Redondants puisque ce sont des sous-ensembles des combinaisons suivantes :

iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP

.

# Rejet du ping
iptables -t mangle -A PREROUTING -p icmp -j DROP

ICMP, ce n’est pas que le ping.
Certains types ICMP doivent être acceptés dans l’état RELATED : destination-unreachable, time-exceedet et parameter-problem.

# Nombre de connexion TCP max/s pour une hote
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP

Cette limite est globale, pas par hôte.

# Anti scan de port
iptables -N port-scanning
iptables -A port-scanning -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 2 -j RETURN
iptables -A port-scanning -j DROP

Je ne vois pas l’intérêt du traitement particulier des ces paquets.
Le drapeau RST sans ACK est invalide. Ces paquets devraient juste être traités comme les autres combinaisons de drapeaux TCP invalides.
La chaîne utilisateur port-scanning n’est appelée nulle part.

# Enregistrer les connexions refusées
iptables -A INPUT -m limit --limit 2/min -j LOG --log-prefix "Packets DROP"

Avec une limitation à 2 par minute, ça ne va pas enregistrer grand-chose.

Merci à tous pour vos retours et Pascal particulièrement pour le détail de sa réponse.

Bon, je laisse tomber iptables, même si comme tu le dis, les règles sont traduites vers nftables.

Je vais réécrire tout en nftables en m’appuyant sur l’exemple fournis par grandtoubab et en tenant compte de vos remarques à tous.

On va partir sur quelque-chose de plus simple et générique.

Sinon, fail2ban par défaut fait du iptables, mais je crois qu’on peut lui faire faire tout en nftables.

Je teste tout ça t reviens vers vous !

/edit: bizarre… nftables n’est pas installé en debian 10 par défaut, normal ? C’est un seveur physique sur OVH que j’ai vu ça.

Reste à savoir si l’image Debian 10 fourni durant l’installation de Debian chez OVH est vanilla, de ce que tu dit j’ai pas l’impression.

Hello,

Voici mes nouvelles règles, pour le moment je n’autorise que 2 ip sur le 2278, avec pas mal de restrictions en amont, en virant d’éventuelles redondances par rapport aux règles iptables, et à la fin, notre ami Fail2ban qui complétera ce qui manque. Qu’en pensez-vous ?

table inet filter {
        chain input {
                type filter hook input priority 0; policy accept;
                ct state { established, related } accept
                tcp flags != syn ct state new log prefix "Premier paquet non SYN" drop
                tcp flags & (fin | syn) == fin | syn log prefix "Port scan possible (1)" drop
                tcp flags & (syn | rst) == syn | rst log prefix "Port scan possible (2)" drop
                tcp flags & (fin | syn | rst | psh | ack | urg) < fin log prefix "Port scan possible (3)" drop
                tcp flags & (fin | syn | rst | psh | ack | urg) == fin | psh | urg log prefix "Port scan possible (4)" drop
                ct state invalid log prefix "Etat conntrack invalide: " flags all counter packets 0 bytes 0 drop
                iifname "lo" accept
                ip protocol icmp accept
                ip6 nexthdr ipv6-icmp accept
                tcp dport { 2278 } ip saddr { IP1, IP2 } accept
                counter packets 0 bytes 0 drop
        }

        chain forward {
                type filter hook forward priority 0; policy accept;
                drop
        }

        chain output {
                type filter hook output priority 0; policy accept;
                accept
        }
}
table inet fail2ban {
        chain INPUT {
                type filter hook input priority 100; policy accept;
        }
}