Die meisten Firewall-Anleitungen fangen mit Regeln an. Das ist der zweite Schritt. Der erste ist herauszufinden, was überhaupt lauscht und der beste Schutz ist, dass ein Dienst gar nicht erst nach außen hört.
Schritt 1: Bestandsaufnahme#
sudo ss -tulpn | grep LISTEN
Die Ausgabe lesen:
| Was dort steht | Bedeutung |
|---|---|
0.0.0.0:443 | alle IPv4-Adressen, von außen erreichbar |
[::]:443 | alle IPv6-Adressen, meist inklusive IPv4 |
127.0.0.1:5432 | nur lokal, von außen nicht vorhanden |
[::1]:5432 | nur lokal über IPv6 |
10.99.0.5:9100 | nur über diese eine Schnittstelle |
Für jede Zeile mit 0.0.0.0 oder [::] eine Frage: Muss das wirklich von außen erreichbar sein? In den meisten Fällen lautet die Antwort nein, Datenbanken, Metrik-Endpunkte, Verwaltungsoberflächen und Debug-Ports gehören hinter einen Reverse-Proxy oder ein VPN, nicht ins offene Netz.
Schritt 2: Dienste lokal binden#
Das ist wirksamer als jede Firewallregel, weil es keine Regel gibt, die man versehentlich löschen kann.
# PostgreSQL — /etc/postgresql/17/main/postgresql.conf
listen_addresses = 'localhost'
# Docker Compose: Port nur lokal veröffentlichen
services:
db:
ports:
- "127.0.0.1:5432:5432" # nicht "5432:5432"
# Prometheus node-exporter — nur über das VPN-Netz
[Service]
ExecStart=/usr/local/bin/node_exporter --web.listen-address=10.99.0.5:9100
Nach jeder Änderung erneut ss -tulpn, die Datei sagt, was gemeint war, ss sagt, was passiert ist.
Schritt 3: Die Grundregel#
Erst jetzt die Firewall, als zweite Verteidigungslinie für den Fall, dass ein Dienst doch nach außen bindet.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iif "lo" accept
ct state invalid drop
# ICMP nicht komplett verwerfen: ohne Fragmentation-Needed bricht die
# Pfad-MTU-Erkennung, und Verbindungen hängen scheinbar grundlos.
ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } accept
ip6 nexthdr icmpv6 icmpv6 type { echo-request, destination-unreachable, packet-too-big, time-exceeded, nd-neighbor-solicit, nd-neighbor-advert } accept
tcp dport 22 ct state new limit rate 10/minute accept comment "SSH"
tcp dport { 80, 443 } accept comment "Web"
counter comment "verworfen eingehend"
}
chain forward {
type filter hook forward priority filter; policy drop;
}
}
sudo nft -c -f /etc/nftables.conf # nur prüfen
sudo systemctl enable --now nftables
sudo nft list ruleset
policy drop trennt jede Verbindung, deren Port nicht erlaubt ist, auch deine SSH-Sitzung, wenn SSH auf einem anderen Port läuft und hier fehlt. Lege vorher einen Rückfall-Timer an:
sudo sh -c 'sleep 120 && nft flush ruleset' &
Läuft die Verbindung noch, brichst du ihn ab. Läuft sie nicht, räumt er in zwei Minuten auf.
Der Fehler, der am häufigsten übrig bleibt: IPv6#
Klassische iptables-Regeln gelten nur für IPv4. Ist IPv6 konfiguriert und der Dienst hört auf [::], ist er über IPv6 erreichbar, während iptables -L beruhigend aussieht.
Die inet-Tabelle oben deckt beides in einem Regelwerk ab. Prüfen lässt sich das nur von außen:
# Von einer anderen Maschine aus — nur eigene Adressen scannen
nmap -Pn -p- --min-rate 2000 203.0.113.10
nmap -6 -Pn -p- --min-rate 2000 2001:db8::10
Ein Scan von der Maschine auf sich selbst läuft über Loopback und sagt nichts über die Erreichbarkeit von außen.
Prüfen, ob die Regeln greifen#
# Trefferzähler pro Regel: welche greift nie, welche zu oft?
sudo nft -a list ruleset | grep counter
# Was wurde in den letzten 24 Stunden verworfen?
sudo journalctl -k --since "24 hours ago" | grep -i 'nft\|drop' | tail -20
Ein Zähler bei null ist entweder eine überflüssige Regel oder ein Hinweis, dass der Verkehr woanders vorbeiläuft, beides lohnt einen Blick.
Was hier bewusst fehlt#
Die ausgehende Richtung. Sie ist die, an der ein Einbruch auffällt, und deshalb ein eigener Beitrag: Ausgehend begrenzen.
Und wenn Docker im Spiel ist, gilt ein Teil der obigen Aussagen nicht mehr, Docker schreibt eigene Regeln und veröffentlicht Ports an der Firewall vorbei. Dazu Docker umgeht deine Firewall.
Geschrieben aus dem laufenden Betrieb: MRMedia betreibt eigene Hosts, Kundendienste und deren Härtung in der EU. Eine veraltete Anleitung ist hier ein Sicherheitsproblem, kein Schönheitsfehler. Korrekturen bitte über Discord.