Thema Iptables: Firewall und IPSet
Abschnitt 1: Installation und Grundeinrichtung
Nun kommt mein Lieblingsthema überhaupt. An dem habe ich viele Stunden und Nächte verbracht :)
Erstmal alles Nötige installieren:
apt install iptables-persistent iptables -y
Bei Iptables wird jedes Protokoll (**IPv4** und **IPv6**) separat behandelt. Die Regeln für IPv4 gelten also nie für IPv6 und umgekehrt.
Um das Ganze "angenehmer" zu machen, werden wir hier mit **Bash-Scripten** arbeiten, da diese die Sache vereinfachen. Dazu wechseln wir erstmal über SSH in den Ordner `iptables`:
cd /etc/iptables
Darin finden wir Folgendes:
-rw-r----- 1 root root 4364 Jun 29 11:00 rules.v4
-rw-r----- 1 root root 849 Jun 29 11:00 rules.v6
Dort werden die **persistenten Regeln** für jedes Protokoll gespeichert.
Schauen wir uns die vorhandenen Regeln einmal an mit `iptables -S` für IPv4 und `ip6tables -S` für IPv6.
Ausgabe für IPv4:
root@server01:~# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
Ausgabe für IPv6:
root@server01:~# ip6tables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
**Alle Türen sind sperrangelweit offen, das müssen wir ändern!**
Da jeder, der damit anfängt, sich schon einmal über die Firewall ausgesperrt hat, gebe ich Ihnen hier mal ein fertiges Script als Grundlage. Ihre Schnittstellen fragen Sie auf der Konsole mit `ip a` ab:
ip a
#!/bin/bash
IPT="/sbin/iptables"
WAN="ens18"
LAN="ens19"
WLAN="ens20"
# Löschen aller Regeln
$IPT -F
$IPT -t nat --flush
$IPT -t mangle --flush
# Policy setzen auf ALLES ablehnen!
$IPT -P INPUT DROP
$IPT -P OUTPUT DROP
$IPT -P FORWARD DROP
$IPT -t nat --policy PREROUTING ACCEPT
$IPT -t nat --policy OUTPUT ACCEPT
$IPT -t nat --policy POSTROUTING ACCEPT
$IPT -t mangle --policy PREROUTING ACCEPT
$IPT -t mangle --policy OUTPUT ACCEPT
# LOOPBACK aktivieren, sonst geht nichts
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# bestehende Eingehende Verbindungen zulassen
$IPT -A INPUT -i $WAN -m state --state RELATED,ESTABLISHED -j ACCEPT
$IPT -A INPUT -i $LAN -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
$IPT -A INPUT -i $WLAN -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
# Alle Verbindungen zulassen für Ausgehend
$IPT -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
# Alle bestehenden Verbindungen zulassen für FORWARD (Weiterleitung)
$IPT -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
# LAN Verbindungen erlauben
$IPT -A FORWARD -i $LAN -o $WAN -m state --state NEW -j ACCEPT
$IPT -A FORWARD -i $WLAN -o $WAN -m state --state NEW -j ACCEPT
# LAN und WLAN und umgekehrt erlauben
$IPT -A FORWARD -i $LAN -o $WLAN -m state --state NEW -j ACCEPT
$IPT -A FORWARD -i $WLAN -o $LAN -m state --state NEW -j ACCEPT
# SSH zulassen um sich nicht auszusperren
$IPT -A INPUT -i $LAN -p tcp --dport 22 -m state --state NEW -j ACCEPT
$IPT -A INPUT -i $WLAN -p tcp --dport 22 -p tcp --dport 22 -m state --state NEW -j ACCEPT
# PING zulassen aber für WAN begrenzen
$IPT -A INPUT -i $WAN -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED,RELATED -m limit --limit 30/minute --limit-burst 60 -j ACCEPT
$IPT -A OUTPUT -o $WAN -p icmp --icmp-type echo-reply -m state --state NEW,ESTABLISHED,RELATED -m limit --limit 30/minute --limit-burst 60 -j ACCEPT
$IPT -A INPUT -i $LAN -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -o $LAN -p icmp --icmp-type echo-reply -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -i $WLAN -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -o $WLAN -p icmp --icmp-type echo-reply -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
#
# --- Grundlegende Sicherheit (Stealth-Scans, ungültige Pakete, Multicast) ---
#
# Stealth-Scans verhindern (kommentarlos verwerfen)
# 2. XMAS-Scan (alle Flags gesetzt)
$IPT -A INPUT -p tcp --tcp-flags ALL ALL -m conntrack ! --ctstate ESTABLISHED,RELATED -j DROP
# 3. Null-Scan (keine Flags gesetzt)
# Ein Paket ohne TCP-Flags ist im regulären Betrieb ebenfalls nicht vorgesehen.
$IPT -A INPUT -p tcp --tcp-flags ALL NONE -m conntrack ! --ctstate ESTABLISHED,RELATED -j DROP
# 4. SYN/FIN-Scan
$IPT -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -m conntrack ! --ctstate ESTABLISHED,RELATED -j DROP
# 5. SYN/RST-Scan
$IPT -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -m conntrack ! --ctstate ESTABLISHED,RELATED -j DROP
# Ungültige Pakete verwerfen
$IPT -A INPUT -p tcp -m state --state INVALID -j DROP
$IPT -A OUTPUT -p tcp -m state --state INVALID -j DROP # Optional
$IPT -A FORWARD -p tcp -m state --state INVALID -j DROP # Nur wenn Routing aktiv
# Multicast nur über UDP zulassen
$IPT -A INPUT ! -p udp -d $NETWORK_MULTICAST -j DROP
$IPT -A FORWARD ! -p udp -d $NETWORK_MULTICAST -j DROP # Nur wenn Routing aktiv
#
# Hier kommt die Blacklist Prüfung hin
#
#
#
#
#
#
#
#
# SNAT für den Internetzugang auch für die Clients
$IPT -t nat -A POSTROUTING -o $WAN -j MASQUERADE
# Einstellungen speichern
netfilter-persistent save
Passen Sie Ihre Schnittstellen oben an, damit auch die richtigen zugewiesen werden. Kopieren Sie sich den Text und führen Sie dann auf der Konsole folgende Schritte aus:
Öffnen der Datei:
nano /etc/iptables/firewall.sh
Mit einem Rechtsklick auf die Konsole wird der Text dort hineinkopiert. Speichern und schließen Sie mit:
STRG + O
STRG + X
Nun müssen Sie das Script ausführbar machen und starten:
chmod a+x /etc/iptables/firewall.sh
/etc/iptables/firewall.sh
Als Ausgabe erhalten wir, wenn kein Fehler im Script ist, folgende beiden Zeilen:
klaus@server01:/etc/iptables# /etc/iptables/firewall.sh
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
Abschnitt 2: IPSet
Zu jeder Firewall gehört **IPSet**.
Damit können Sie sich ganz einfach Blacklists einrichten, und auch **Fail2ban** profitiert davon, wenn es dafür konfiguriert ist. Aber der Reihe nach.
Installation:
apt install ipset -y
Pflegehinweise für IPSet
# Set erstellen, sofern nicht vorhanden (-exist)
ipset create 'setname' hash:net -exist hashsize 16384 maxelem 65536
# Set löschen
ipset destroy 'setname'
# Speichert nur ein bestimmtes Set
ipset save 'setname' > ipset_backup.txt
# Stellt ein Set wieder her
ipset restore 'setname' < ipset_backup.txt
# Ein komplettes Set in eine Datei schreiben
ipset list 'setname' > ausgabe.txt
# Nur den Kopf anzeigen, was wichtig als Info ist.
ipset list -t 'setname'
# IP oder CIDR zum Set hinzufügen
ipset add 'setname' 1.2.3.4
ipset add 'setname' 1.2.3.0/24
# IP oder CIDR vom Set löschen
ipset del 'setname' 1.2.3.4
ipset del 'setname' 1.2.3.0/24
# Testen ob eine IP oder CIDR im Set vorhanden ist
ipset test 'setname' 1.2.3.4
ipset test 'setname' 1.2.3.0/24
Ausgabe der vorhandenen Listen
Folgend mal die Ausgabe bei mir, um zu sehen, welche Listen ich im System habe:
root@server01:~# ipset list -t
Name: blacklist
Type: hash:net
Revision: 7
Header: family inet hashsize 131072 maxelem 565536 bucketsize 12 initval 0x97b45a01
Size in memory: 4867344
References: 2
Number of entries: 144246
Name: dach
Type: hash:net
Revision: 7
Header: family inet hashsize 65536 maxelem 565536 bucketsize 12 initval 0xaaf3a9de
Size in memory: 685440
References: 1
Number of entries: 15808
Name: whitelist
Type: hash:net
Revision: 7
Header: family inet hashsize 65536 maxelem 565536 bucketsize 12 initval 0x62435b6c
Size in memory: 2640
References: 2
Number of entries: 14
Name: le-whitelist
Type: hash:net
Revision: 7
Header: family inet hashsize 65536 maxelem 100 bucketsize 12 initval 0x224e7fdd
Size in memory: 3168
References: 0
Number of entries: 25
Erstellen wir unser erstes Set. Die Angabe **`-exist`** legt es nur an, wenn es noch nicht vorhanden ist. **`hash:net`** ist für Netzwerkadressen, perfekt für eine Firewall. `hashsize` und `maxelem` geben die Größe des Sets an. Die Angaben hier sind mehr als ausreichend!
ipset create blacklist hash:net -exist hashsize 16384 maxelem 65536
Im Internet gibt es frei verfügbare **CIDR-Listen** von ganzen Ländern, zum Beispiel bei ipdeny.com. Mit diesen Listen lassen sich ganze Länder sperren, und wenn man die "richtigen" sperrt, ist der Spam auch gleich verschwunden :) Da das Ganze recht mühsam ist, jedes CIDR per Befehl in die Liste zu bekommen, kann man unter Linux wunderbar ein Bash- oder PHP-Script nutzen.
Hat man dann eine solche Blacklist erstellt, wird diese ganz einfach in Iptables eingebunden mit:
# Blacklist aus ipset
$IPT -A FORWARD -i $IFACE_WAN -p tcp --syn -m set --match-set blacklist src -j DROP
$IPT -A OUTPUT -o $IFACE_WAN -m set --match-set blacklist dst -j DROP
$IPT -A INPUT -i $IFACE_WAN -p tcp --syn -m set --match-set blacklist src -j DROP
Die Regeln sperren alles aus dem Set auf **INPUT**, **OUTPUT** und **FORWARD**. Wenn alle Ihre Server dieses IPSet nutzen, können Sie auf OUTPUT und FORWARD verzichten.
Beachten Sie bei INPUT und FORWARD die Angabe **`src`** (Quelle) und bei OUTPUT **`dst`** (Ziel). Zudem werden hier mit der Angabe **`--syn`** nur neue Verbindungen geblockt, was sinnvoll ist.
Das Ganze geht natürlich auch für **`ACCEPT`**, was den Zugriff unheimlich erleichtert. Mein E-Mail-Server z.B. blockt den ganzen Orient, inkl. Russland, China, Nord-Korea und viele afrikanische Länder, sowie Mexiko und Brasilien für eingehende E-Mails.
Für den Zugriff auf meine Postfächer nutze ich diese Regeln, die nur 15 IP-Adressen Zugriff gewährt, was sehr sicher ist. Dazu noch eine Begrenzung der Verbindungen, und DDoS fällt auch aus:
$IPT -t nat -A PREROUTING -i $IFACE_WAN -d $IP_WAN -p tcp -m multiport --dports $EMAIL_PORT -j DNAT --to-destination $IP_MAIL_SERVER
$IPT -A FORWARD -i $IFACE_WAN -o $IFACE_LAN -d $IP_MAIL_SERVER -p tcp -m multiport --dports $EMAIL_PORT -m state --state NEW -m limit --limit $RATE_LIMIT_CONNECTIONS/minute --limit-burst $RATE_LIMIT_BURST -m set --match-set whitelist src -j ACCEPT
Was soll ich sagen, seitdem ist es sehr ruhig geworden.