OpenBSD 7.7 als robuste Firewall‑Basis: eine pf.conf und sysctl.conf, die Dir den Rücken freihält

OpenBSD ist seit Jahren berüchtigt für sein kompromissloses Sicherheits‑Ethos: klare Defaults, sauberer Code, „secure by default“ nicht als Schlagwort, sondern als Arbeitsauftrag. Wenn Du eine Firewall suchst, die im Alltag vor allem zuverlässig und nachvollziehbar arbeitet, hast Du mit OpenBSD eine solide Grundlage. Gleichzeitig gilt: starke Defaults sind großartig, doch ein paar gezielte Stellschrauben erhöhen das Sicherheitsniveau und die Vorhersagbarkeit spürbar, ohne dass daraus ein fragiles Speziallabor wird.
Wir möchten mit diesem Artikel eine praxistaugliche Baseline liefern, die kleine Netze, Home‑Labs und viele KMU‑Setups souverän absichert und dabei lesbar bleibt.
Statt langer Checklisten und willkürlicher Tuning‑Tipps bekommst Du hier fundierte Entscheidungen mit klarer Begründung. Wir zeigen Dir, warum eine bestimmte Option gesetzt wird, welche Risiken sie adressiert und welche Nebenwirkungen Du im Hinterkopf behalten solltest. Das Ziel ist nicht, jedes theoretische Angriffsszenario abzudecken, sondern Dir einen verlässlichen Startpunkt zu geben: schlanke Regeln, wenige Ausnahmen, eindeutiges Verhalten.
Dieser Leitfaden verfolgt eine klare Linie: explizit erlauben, ansonsten blocken. Von außen nach innen gibt es nur das, was der Router selbst braucht; von innen nach außen lassen wir nur das passieren, was Du tatsächlich willst. DNS wird sichtbar und kontrollierbar gehalten. DoH, DoT, DoQ und QUIC bekommen keine stillen Nebenwege, damit Dir keine „unsichtbaren“ Kanäle durchrutschen. Zustände werden bewusst an Interfaces gebunden, damit Verbindungen dort bleiben, wo sie entstanden sind. Das macht das System berechenbar und die Fehlersuche erträglich. Und weil Transparenz mehr wert ist als zehn zusätzliche Tricks, sind alle kritischen Wege mit Labels versehen: Du siehst im Betrieb sofort, was genutzt wird, was scheitert und wo Du nachschärfen musst.
Damit das greifbar bleibt, arbeiten wir mit zwei pf‑Profilen, zwischen denen Du wählen kannst: einer kompakten Router‑Only‑Variante für klassische LAN‑an‑Internet‑Szenarien und einer Router+DMZ‑Variante, wenn Du Dienste kapseln willst. Wir erzwingen DNS für Clients konsequent nur zu 1.1.1.1 (optional 1.0.0.1 als Fallback). Das ist keine Spitzfindigkeit, sondern ein bewusstes Architekturmerkmal: Du bekommst damit Sichtbarkeit und Kontrolle zurück. Wenn eine Anwendung anderes will, fällt sie auf und Du entscheidest bewusst, ob und wo Du eine Ausnahme setzt.
Die sysctl.conf ergänzt diese Grundhaltung auf Kernel‑Ebene. OpenBSD bringt bereits viel mit, doch einige Schalter bringen messbaren Zugewinn an Robustheit: eine harte Malloc‑Konfiguration, die klassische Speicherfehler früher und lauter scheitern lässt; das Deaktivieren von SMT/Hyper‑Threading, wenn Dir Seitenkanalrisiken schlicht nicht den Hauch eines Nutzens bringen; W^X, das im Zweifel Prozesse lieber sauber beendet als in gefährlichen Grauzonen weiterlaufen lässt; das Abschalten von Redirects und entbehrlichen Tunnel‑Protokollen; moderne TCP‑Optionen und moderate Rate‑Limits, die Netz‑„Lärm“ dämpfen, ohne legitime Funktion zu brechen. Das sind keine spektakulären „Tweaks“, sondern konsequente Hygiene: weniger Angriffsfläche, weniger Überraschungen, stabileres Verhalten unter Last.
Nicht im Fokus sind hochspezialisierte Zielangriffe oder vollumfängliche IDS/IPS‑Szenarien. Wenn Du ein mehrstufiges Monitoring, eine tiefe Protokoll‑Inspektion oder Threat‑Intelligence‑Feeds integrieren willst, ist diese Konfiguration kein Hindernis; sie ist das Fundament, auf dem Du solche Bausteine später geordnet ergänzen kannst. Ebenso decken wir hier bewusst keine komplexen Multi‑WAN‑Politiken, aufwendige Portweiterleitungslandschaften oder exotische Overlay‑Netze ab. Das alles lässt sich realisieren, aber nicht, ohne die Klarheit der Baseline zu verwässern.
Die angestrebte Lesbarkeit bedeutet auch, dass wir auf Mechanik statt Magie setzen. NAT ist dort statisch, wo Echtzeitprotokolle davon leben, und dynamisch, wo es keine Rolle spielt. QUIC bleibt draußen, damit DNS nicht heimlich in TLS‑Strömen verschwindet. IPv6 ist zunächst geblockt, damit Du kein „half‑open IPv6“ betreibst, bei dem Clients v6 bevorzugen, während die Firewall v6 nicht kontrolliert – im Artikel bekommst Du eine saubere Anleitung, wie Du IPv6 später richtig aktivierst, wenn Du es brauchst. Und überall dort, wo es hilft, sind Grenzfälle mit Labels markiert. Nicht, damit die Logfiles bunter werden, sondern damit sie antworten: Wer hat versucht, DoT zu sprechen? Welche Hosts rennen in die Anti‑Rebind‑Regel? Was triggert die Egress‑Sperren?
Für wen ist das gedacht? Für Dich, wenn Du Administration als Handwerk verstehst und lieber eine Stunde in eine saubere Basis investierst als drei Wochen in das Jagen merkwürdiger Seiteneffekte. Für Dich, wenn Du Dein Netz verstehen willst, statt Dich von Default‑Erlaubnissen überraschen zu lassen. Und auch für Dich, wenn Du Dich „zwischen den Stühlen“ siehst: nicht groß genug für SOC/Blue‑Team‑Apparat, aber zu anspruchsvoll für „Router aus dem Baumarkt“. Die hier vorgestellte Baseline ist kein Zaubertrick, sondern ein vernünftiger Standard – bewusst klein genug, um sie zu beherrschen, und gleichzeitig stabil genug, um sie lange zu behalten.
Threat‑Model: wogegen wir uns stellen, und wogegen nicht
Die Baseline ist für Umgebungen gedacht, in denen Du keine dedizierte Blue‑Team‑Mannschaft hast, aber verlässliche Standards willst. Sie schützt vor den üblichen Dingen, die täglich gegen Deine Kante prallen: breit gestreute Scans, opportunistische Exploits, Protokoll‑Mißbrauch wie „DNS via alles“, falsch konfigurierte Freigaben oder großzügige Egress‑Policies, die Datenabfluss erst ermöglichen. Sie kapselt optionale Server in einer DMZ und verhindert damit seitliche Bewegungen ins LAN. Nicht im Fokus sind hochspezialisierte Zielangriffe oder vollumfängliche IDS/IPS‑Szenarien – die könntest Du später auf dieser Basis ergänzen.
Designprinzipien: kleine Angriffsfläche, klare Zuständigkeiten
Die Konfiguration folgt einigen Leitlinien, die Dir auch bei zukünftigen Anpassungen helfen:
Fail‑closed. Wo etwas nicht ausdrücklich erlaubt wird, bleibt es zu. Das gilt inbound und outbound. So merkst Du im Test früh, was eine Anwendung wirklich braucht – und behältst die Kontrolle.
Deterministische Zustände. if-bound sorgt dafür, dass eine Verbindung an das Interface gebunden bleibt, an dem sie entstanden ist. Gerade auf Single‑WAN‑Routern setzt das Stochern in magischen „floating“ States ein Ende und macht Fehlersuche einfacher.
- Egress‑Minimalismus. Von innen nach außen passiert nur, was tatsächlich notwendig ist: klassisches Web, Mail‑Submission, definierte UDP‑Ranges für VoIP/WebRTC – und DNS ausschließlich dorthin, wo Du es haben willst.
- Transparenz statt Ratespiel. QUIC wird geblockt, DoH/DoT/DoQ ebenso. Ja, das ist unbequem für manche Apps. Dafür gibt es klare Sicht: DNS ist DNS, TLS ist TLS. Wer Schatten‑DNS braucht, fällt auf.
- Robuste Defaults. Scrubbing, MSS‑Begrenzung, randomisierte IDs, Bogon‑Filter, Anti‑Spoofing, TCP‑Flag‑Hygiene, sinnvolle Rate‑Limits für ICMP und RST. Nichts davon ist spektakulär – zusammen ergibt es solide Hygiene.
- IPv6 bewusst. Standardmäßig ist IPv6 aus. Wer es will, bekommt im Artikel eine saubere Einbauanleitung. „Half‑open IPv6“ (Firewall kann’s nicht, Clients aber schon) vermeiden wir konsequent.
Die sysctl.conf – Sicherheitshebel im Kernel, die wirklich zählen
OpenBSD bringt bereits starke Defaults mit, aber einige Stellschrauben erhöhen das Sicherheitsniveau und die Vorhersagbarkeit spürbar. Hier die wichtigsten Punkte, ohne endlose Checklisten, dafür mit klarer Begründung.
- Speicherhärtung (vm.malloc_conf=CFGJRS). Guard‑Pages, Junk‑Füllmuster, Red‑Zone und Canaries machen klassische Speicherfehler deutlich schwerer ausnutzbar und sorgen dafür, dass Prozesse „laut“ scheitern statt still zu korrumpieren. Der geringe Overhead lohnt sich in praktisch allen Router‑Szenarien.
- CPU/Hardware: SMT aus, Aperture zu. hw.smt=0 reduziert Seitenkanalrisiken (Hyper‑Threading) – auf Routern ist der Durchsatzverlust meist sehr gering. machdep.allowaperture=0 schließt /dev/mem‑ähnliche Abkürzungen; für Headless‑Router genau richtig. Wer X11/KMS braucht, weiß, was er tut, ansonsten bleibt das zu.
- Routing & Protokolle: IPv4 an, IPv6 bewusst aus. net.inet.ip.forwarding=1 macht Deinen Knoten zum IPv4‑Router. net.inet6.ip6.forwarding=0 verhindert „zufälliges“ IPv6‑Routing. Dazu schalten wir unnötige Tunnel wie IP‑in‑IP, GRE, ESP/AH und EtherIP ab. Weniger Krypto‑/Kapselmechanik heißt weniger Angriffsfläche und weniger Überraschungen im Betrieb.
- Legacy‑Stolperfallen entschärfen. Directed Broadcasts sind aus, Redirects ignoriert, sowohl für IPv4 als auch für IPv6. ICMP‑Redirects sind ein klassischer Fußangel; wer Pfade ernsthaft umbiegen will, soll das bewusst in Routing oder PF tun, nicht nebenbei.
- ICMP mit Augenmaß. Broadcast‑Echo antworten wir nicht, Timestamps/Netmask ebenfalls nicht; Error‑Pakete bekommen ein sinnvolles Rate‑Limit. Das dämpft DDoS‑Noise, ohne legitime Funktion zu brechen. ICMP ist kein Feind, aber es braucht Leitplanken.
- UDP/TCP‑Härtung statt Hokuspokus. UDP‑Checksummen sind Pflicht; sinnvolle Socket‑Puffer verhindern unschöne Drops. Für TCP bleiben moderne Features wie Window Scaling, Timestamps und SACK an – sie bringen spürbare Stabilität. ECN wird aktiv; das schadet in heutigen Netzen selten und hilft unter Last. SYN‑Cache‑/Bucket‑Limits und RST‑Rate‑Limit fangen typische Scan‑Wellen ab.
- Queues, BPF und W^X. Eine längere If‑Queue reduziert Drops bei Lastspitzen. Größere BPF‑Puffer sind ein Geschenk an Dich selbst beim Debuggen. kern.wxabort=1 setzt W^X kompromisslos durch: Code ist entweder schreibbar oder ausführbar, nicht beides. Verstöße führen zum Prozessabbruch – „fail‑closed“, genau wie gewünscht. Und die Swap‑Verschlüsselung bleibt an, damit nie sensible Reste im Klartext auf dem Massenspeicher landen.
Diese sysctl‑Wahl ist bewusst unspektakulär. Sie verschiebt die Kurve vom „läuft meistens“ zu „verhält sich auch unter Stress konsistent“. Wichtig ist nur: lade die Datei sauber mit sysctl -f, prüfe ein paar Kennzahlen (sysctl -n net.inet6.icmp6.errppslimit, netstat -m, pfctl -s memory) und mach Dir bei größeren Änderungen (z. B. am mbuf‑Budget) bewusst, was PF‑Limits wie set limit frags danach bedeuten.
Die pf.conf: Regeln, die Du verstehst
pf bietet Dir unzählige Möglichkeiten. Unsere Baseline nimmt davon genau so viel, wie Du für robuste Standards brauchst. Nicht mehr, nicht weniger.
Makros, Tabellen und Labels – Struktur ist die halbe Miete
Zuerst klar definierte Interfaces und Netze: WAN, LAN und – in der DMZ‑Variante – DMZ. Dazu Tabellen für Bogons, Abuser, Scanner und eine Watch‑Liste für verdächtige DoH‑Endpunkte. Diese Tabellen sind nicht nur Zierde: durch persist überleben sie Reloads, und über „overload“ landen auffällige Quellen automatisch in ihnen. Konsequent gesetzte Labels an Regeln geben Dir später im Betrieb exzellente Sicht, ohne aufwändige pcap‑Akrobatik: pfctl -vvsr oder systat pf erzählen Dir, wo das Leben pulsiert.
Globale Optionen – vorhersagbares Verhalten
set block-policy drop und „aggressive“ Optimization sind konservative Defaults mit Sinn. set state-policy if-bound bindet Verbindungen an das Interface, an dem sie entstanden sind. Wir definieren Limits für States, Frags und Src‑Nodes, setzen adaptive Timeouts, und aktivieren syncookies adaptiv. Sie helfen, wenn das Wasser wirklich hoch steht. loginterface zeigt Dir statistisch, was über das WAN geht; set skip on lo0 vermeidet Selbstbeschuss.
Standardmäßig ist IPv6 in pf geblockt. Das entspricht der sysctl‑Vorgabe und verhindert „half‑open IPv6“. Wer IPv6 produktiv will, schaltet es bewusst und sichtbar frei.
ICMP inbound: offen genug, um gesund zu sein
Wir erlauben am WAN‑Interface gezielt ICMP‑Echo und „Unreachable“ – jeweils zustandsbehaftet und mit moderatem Rate‑Limit. Das stärkt Debuggability (wie willst Du sonst zuverlässig MTU‑/Pfad‑Probleme finden?) und schützt gleichzeitig vor den üblichen Ping‑Fluten. Alles andere – insbesondere Redirects – bleibt aus.
Scrubbing: weniger Zerfall, weniger Frust
Eingehend wie ausgehend scrubben wir Pakete: randomisierte IP‑IDs, eine konservative Mindest‑TTL, MSS‑Kappung auf 1440 (erfahrungsgemäß ein gesunder Wert), und TCP‑Reassembly. Das verhindert, dass fragmentierte oder grenzwertige Pakete Deine States verstopfen, und reduziert PMTU‑Schluckauf spürbar. MSS‑Tuning via sysctl braucht es dann fast nie.
NAT: statisch, wo Echtzeit zählt. Dynamisch, wo’s egal ist
UDP bekommt statische Ports. Das ist Gold wert für VoIP/WebRTC, für Gaming und viele Realtime‑Protokolle. Alles andere geht über einen hohen Ephemeral‑Bereich, damit Dich Egress‑Zuordnung im Paketmitschnitt nicht zum Wahnsinn treibt und weil Du Kollisionen so zuverlässig vermeidest. NAT greift für alles außer sehr gezielt definierte Management‑Ziele – so verhinderst Du auch hier überraschende Pfade.
Anti‑Spoofing, Bogons, Null‑Ports
antispoof sitzt wachsam an allen relevanten Interfaces. Pakete, die am WAN mit kaputter Quellroute ankommen, fliegen sofort. Bogons inbound und outbound werden geblockt; was aus 10/8 oder 127/8 ins Internet will, hat im Regelfall andere Probleme. Ebenfalls aufgeräumt wird bei Null‑Ports und unplausiblen TCP‑Flags – das ist kein Hexenwerk, aber es spart Dir Ärger mit Scannern und Tools, die „kreativ“ testen, was hinter Deiner Adresse steckt.
Default‑Deny: Der große Besen
Nach dieser Hygiene kommt der harte Schnitt: block all. Von hier an beginnt die Welt der bewussten Ausnahmen.
Inbound am WAN: nur, was der Router selbst braucht
Eingehend erlauben wir am WAN lediglich DHCP‑Traffic, falls der Upstream es verlangt. Danach ist Feierabend. Eine öffentliche DMZ, die von außen erreichbar sein soll, ist nicht Zweck dieser Baseline; dafür würdest Du bewusst Portweiterleitungen definieren – und auch dann bitte sehr sparsam.
QUIC: HTTP/3 bleibt draußen
Wir sperren UDP 80/443 auf dem WAN‑Interface. Das nimmt QUIC die Luft. Warum so streng? Weil QUIC ein bequemer Tunnel ist – auch für DoH‑Spielarten und andere „Alles‑in‑einer‑Leitung“-Tricks. Wenn Du später einzelne Ziele per HTTP/3 wirklich willst (und weißt warum), kannst Du Ausnahmen definieren. Die Baseline geht erstmal auf Transparenz vor Geschwindigkeit.
Sichtbarkeit für DoH/DoT/DoQ und klare Grenzen
DoT (853/TCP) und DoQ (784/UDP) werden als Egress geblockt und inbound geloggt. Im LAN/DMZ markieren wir Verbindungen zu bekannten DoH‑Hosts explizit mit Labels – ohne sie pauschal zu unterbinden, sofern Du das möchtest. In der strengen Variante sperrst Du DoH vollständig, in der weichen lässt Du es sichtbar und beobachtest erst. Der Punkt ist: Du siehst, wenn Clients verdecktes DNS versuchen.
Admin‑Zugang zur Firewall: knapp und gedrosselt
SSH von LAN zur Firewall ist erlaubt, mit State, Flag‑Hygiene und sanfter Ratenbegrenzung. Für Upstream‑Management‑Ziele (z. B. die GUI eines vorgeschalteten Modems/Routers) gibt es gezielte Pässe; auch hier dämpfen (max-src-conn-rate) kleine Fehlstürme. Labels helfen Dir später, genau diese Wege im Blick zu behalten.
DNS‑Politik ohne lokalen Resolver: erzwingen statt hoffen
Der zentrale Punkt dieser Baseline: Clients im LAN (und in der DMZ, falls vorhanden) dürfen DNS ausschließlich zu 1.1.1.1 und optional 1.0.0.1, jeweils auf Port 53/TCP+UDP. Alles andere zu Port 53 wird geblockt und geloggt. Das ist nicht „nice to have“, sondern entscheidend für Deine Sichtbarkeit. Du siehst im Betrieb sofort, wenn ein Gerät versucht, einen anderen Resolver zu nutzen – oder DoH/DoT/DoQ, die Du getrennt unterbindest. Du kannst diesen Ansatz jederzeit auf einen anderen externen Resolver drehen; die Mechanik bleibt identisch.
DMZ: keine Seitentüren, keine Kurzschlüsse
In der DMZ‑Variante gilt: keine Intra‑DMZ‑Kommunikation, keine Rückwege ins LAN, und ganz gezielte Egress‑Pässe für die Dienste, die dort leben (klassisch Web, Mail‑Submission, VoIP/WebRTC‑UDP‑Ranges). Der Weg zur GUI eines Upstream‑Geräts bleibt für die DMZ tabu; das verhindert, dass ein kompromittierter Server ausgerechnet Dein Management‑Netz berührt. Alles andere ist blockiert und geloggt, damit Du im Fehlerfall die eine fehlende Schraube schnell findest.
Outbound‑Risiken dämpfen: Klassiker zu
Nach außen sperren wir die bekannten Risikodienste: SMB/NetBIOS, RPC/NFS, TFTP, SNMP, RDP/VNC/WinRM, opportunistisches SMTP. Jedes davon hat seine Berechtigung im internen Netz oder auf bewusst definierten Pfaden – im Internet hat es aus verlässlicher Admin‑Sicht erstmal nichts zu suchen. Wenn Du eine begründete Ausnahme brauchst, definierst Du sie bewusst und mit Label.
Die Firewall selbst: raus darf sie, aber sichtbar
Die Firewall selbst darf ins Internet, wiederum mit States, Limits und Label. Das brauchst Du für Updates, Pakete und Diagnose. Übertreibe es nicht: die Kiste ist Router und Wachhund, kein Browser‑Terminal.
Anti‑Rebind, LAN→DMZ und das große Aufräumen
Zwischen LAN und DMZ erlauben wir nur bewusst definierte Pfade (z. B. Clients zum DMZ‑Dienst), der Rückweg bleibt zu. Anti‑Rebind‑Regeln verhindern, dass Clients intern geschützte Ziele via DNS‑Tricks über die Firewall ansprechen. Und überall dort, wo nichts mehr zu sagen ist, sagt PF klar „nein“ – mit return an Stellen, an denen ein schneller Fehlerton Dir die Fehlersuche erleichtert.
Router‑Only vs. Router+DMZ: Welches Profil passt zu Dir?
Wenn Du lediglich ein LAN ans Internet hängen willst, ist die Router‑Only‑Variante ideal. Sie ist kompakt, übersichtlich und trotzdem hart. Du bekommst Anti‑Spoofing, Bogon‑Filter, strenge Egress‑Policy, DNS‑Erzwingung auf 1.1.1.1/1.0.0.1, DoH/DoT/DoQ‑/QUIC‑Blockaden, Admin‑SSH von LAN zur Firewall und saubere Defaults für Scrubbing, States und Limits.
Sobald Du Dienste hostest – selbst wenn sie nur intern genutzt werden –, ist Router+DMZ sinnvoll. Eine DMZ kapselt Fehler und reduziert die Wahrscheinlichkeit, dass ein kompromittierter Dienst als Sprungbrett in Dein LAN funktioniert. Intra‑DMZ bleibt zu; Egress ist whitelist‑basiert und enger als im LAN. DNS ist identisch streng, NTP bleibt dicht, bis Du ihn wirklich brauchst.
IPv6 richtig einschalten
Die Baseline blockt IPv6, damit nichts „halbgar“ offensteht. Wenn Du IPv6 brauchst, aktiviere es gezielt und konsistent: Routing per sysctl, passende pf‑Regeln für inet6, ein sauberer Egress‑Plan (ja, auch hier DNS‑Erzwingung – nur eben für v6), und klare Entscheidungen zu RA/DHCPv6. Spiegel die guten Ideen aus der v4‑Welt: Anti‑Spoofing, Default‑Deny, QUIC/DoH/DoQ‑Management, und sichtbare Ausnahmen – nicht mehr, nicht weniger. Der wichtigste Tipp: führe v6 nicht still nebenbei ein. Wenn es da ist, dann richtig – sonst lieber noch nicht.
Betrieb, Diagnose und Forensik: lieber messen als vermuten
Eine harte Policy ist nur dann gut, wenn Du sie im Alltag lesen kannst. pf hilft Dir dabei über drei Kanäle:
Labels. Jede relevante Regel trägt ein sprechendes Label. Du siehst in pfctl -vvsr, welche Wege genutzt werden, welche blocken, und wo es rummst. Im Alltag reicht das oft schon, um Probleme einzugrenzen.
Tabellen. Mit pfctl -t <table> -T show liest Du Abuser‑/Scanner‑Einträge. „overload“ füllt diese Tabellen automatisch, wenn Clients unangemessen viele Verbindungen aufreißen. Das ist keine Strafe, sondern ein Sicherheitsgurt – wer Slips baut, rutscht nicht gleich durch alle Regeln.
Minimal‑pcap. tcpdump ist Dein Freund, aber setze ihn gezielt ein. Für die DNS‑/DoH‑Kontrolle reichen oft kurze Blicke wie
tcpdump -n -e -ttt -i $wan 'port 53 or port 853 or (udp and port 784)'.
Das ist Forensik mit Plan, nicht „Wireshark bis die Augen tränen“.
Gesunder Testkanon. Wenn Du Regeln änderst, kompilierst Du sie erst ohne zu laden (pfctl -nf /etc/pf.conf). Danach pfctl -f – und wenn es knallt, helfen Dir Labels und Tabellen bei der Korrektur. Für DNS‑Erzwingung probierst Du aktiv: drill @1.1.1.1 openbsd.org muss gehen, drill @9.9.9.9 openbsd.org muss blockiert werden. Für QUIC testest Du zum Beispiel, dass ein Browser bei curl -I --http3 https://example.com nicht über UDP geht; das Ergebnis sollte sauber auf HTTP/2 zurückfallen. DoT/DoQ validierst Du mit einem absichtlichen Verbindungsversuch zu 1.1.1.1:853 bzw. UDP 784 – er muss scheitern, und Du solltest den Block im Label‑Zähler sehen.
Ein Tipp für Änderungen an Egress‑Filtern: Wenn Du etwas öffnest, markiere es temporär mit einem sehr aussagekräftigen Label und schau nach einer Woche, ob es wirklich genutzt wird. Was keiner nutzt, fliegt wieder raus. So bleibt Deine Baseline schlank.
Performance‑Überlegungen ohne Folklore
Das Set‑up ist nicht „auf Kante“ getunt, sondern auf Stabilität. Einige Konsequenzen sind wichtig:
- QUIC‑Block kann einzelne Seiten marginal verlangsamen. Das ist ein bewusster Tausch: Sichtbarkeit vor Speed. Wenn Du valide Gründe hast, HTTP/3 zuzulassen, mache es zielgerichtet (Ziele in eine Tabelle, Label dran, fertig).
- ECN an ist heute in den meisten Netzen unkritisch. Wenn irgendwo exotische Middleboxes stehen, die ECN nicht mögen, siehst Du es schnell und kannst ECN im Einzelfall zurücknehmen – die Baseline macht es Dir nicht schwer.
- Statische UDP‑NAT‑Ports sind ein Geschenk an Echtzeitprotokolle. Wer je WebRTC‑Fehler jagte, weiß, wie wertvoll das ist. Es kostet Dich nichts, außer der bewussten Entscheidung, die NAT‑Portvielfalt bei UDP nicht als „Sicherheitsfunktion“ zu missverstehen.
- If‑Queues und BPF‑Puffer sind pragmatisch dimensioniert: genug Luft, um Lastspitzen auszuhalten und Debug‑Sessions nicht an 4 KB Puffern scheitern zu lassen. Wer wirklich bis an das Durchsatzlimit rennt, misst und passt an – nicht umgekehrt.
Häufige Stolpersteine und wie Du sie elegant umgehst
- „Meine App geht nur mit DoH!“ Dann braucht sie eine Ausnahme oder, besser, eine ehrliche Bewertung. DoH ist nicht per se böse, aber in Unternehmens‑/Heimnetz‑Kontrolle kontraproduktiv. Du kannst gezielte Hosts in eine Allow‑Tabelle nehmen; belasse es bei einer bewussten Ausnahme, nicht bei einer generellen Öffnung.
- „Video‑Call stottert.“ Prüfe zuerst, ob die UDP‑Ranges für Deinen Anbieter abgedeckt sind (Zoom/Teams/WebRTC). Statische UDP‑Ports helfen, aber ohne passenden Egress‑Korridor wird’s nichts. Passe gezielt an, nicht pauschal.
- „Mail‑Client kann nicht direkt senden.“ Richtig, Port 25 outbound ist dicht. Mail gehört via Submission (465/587) zum eigenen Provider oder Server, nicht direkt ins Internet. Definiere, wenn nötig, die Submission‑Ports als erlaubte Egress‑Ziele.
- „IPv6 plötzlich kaputt.“ In dieser Baseline ist v6 blockiert. Wenn Clients v6 bevorzugen, aber die Firewall es nicht routet, entstehen unschöne Timeouts. Entweder Du schaltest v6 richtig an (mit Regeln) – oder Du sagst es den Clients (Router Advertisements/ND) klar: hier gibt’s noch kein v6.
- „Nach Regeländerung komische Effekte.“ Denke an States. Alte States überleben per Default. Wenn Du eine grundlegende Policy änderst (z. B. Egress‑Port neu), leere gezielt die betroffenen States (pfctl -k …) oder, im Zweifel, die Gesamtheit (pfctl -F state). Danach ist die Welt konsistent.
Warum diese Baseline „sicher“ ist und was Sicherheit hier bedeutet
Sicherheit ist nie absolut. Aber sie ist konkret messbar, wenn Du klare Ziele definierst und Deinen Pfad dorthin ehrlich überprüfst. Diese Baseline senkt die Angriffsfläche, weil sie
- jede Inbound‑Fläche minimiert,
- Egress zur Ausnahme und nicht zur Regel macht,
- DNS erzwingt und sichtbar hält,
- verschleierte Pfade (QUIC/DoH/DoT/DoQ) konsequent unterbindet,
- Pseudo‑Funktionen (Redirects, Broadcasts) deaktiviert,
- robuste TCP/ICMP‑Defaults setzt,
- Zustände deterministisch macht,
- und Dir Werkzeuge in die Hand gibt, die Nutzung im Alltag zu beobachten.
Gleichzeitig bleibt die Konfiguration wartbar. Sie ist nicht deshalb „sicher“, weil sie 3000 Zeilen hat, sondern weil Du jede Zeile erklären kannst.
Migration: so gehst Du vor
Wenn Du von einer bestehenden pf‑Konfiguration kommst, geh schrittweise:
- sysctl zuerst. Lade die Härtung, die keinerlei Dienstverfügbarkeit bricht. Prüfe die Logs, ob irgendwo ungewöhnlich viel ICMP‑ oder RST‑Noise anfällt.
- pf‑Policy daneben testen. Verwende pfctl -nf und ein Lab‑Netz oder Maintenance‑Fenster. Achte beim ersten Aktivieren auf SSH‑Zugriff von LAN zur Firewall; nichts ist ärgerlicher als sich selbst auszusperren.
- Egress scharf ziehen. DNS‑Erzwingung aktivieren und beobachten. Danach schrittweise die klassischen Risikodienste schließen. Ein, zwei Wochen Monitoring helfen, blinde Flecken zu finden.
- DMZ einziehen (falls nötig). Dienste umziehen, Intra‑DMZ und DMZ→LAN zu. Nur die wirklich nötigen Egress‑Wege öffnen. Beobachten, nachschärfen.
- IPv6 bewusst entscheiden. Entweder richtig aktivieren oder aus lassen und für Klarheit bei den Clients sorgen.
Mit jeder Stufe wächst die Sicherheit, ohne dass Du Dich mit einem Big‑Bang lahmlegst.
Was Du später einfach erweitern kannst
Diese Baseline ist ein Fundament, kein Käfig. Typische Erweiterungen:
- gezielte Ausnahmen für QUIC/DoH wenn Du validierte Gründe hast; immer mit Tabelle und Label.
- Site‑to‑Site‑VPNs bewusst und mit minimaler Angriffsfläche; die sysctl‑Defaults lassen Dir freie Hand, solange Du die entsprechenden Protokolle explizit zulässt.
- Monitoring/Alerting pf‑Zähler und systat pf eignen sich hervorragend für einfache Metriken. Wer mehr will, schickt pf‑Logs an ein zentrales System.
- IPv6 vollständig gespiegelt zur v4‑Logik, nicht als Fremdkörper.
Ein Wort zu Upgrades und Pflege
OpenBSD hält seine Versprechen – aber lies bei Upgrades die Release‑Notes, insbesondere zu pf‑Syntax und Kernel‑Defaults. Labels, Tabellen und klare Makros helfen Dir, die Konfiguration zwischen Versionen schnell zu prüfen. Bewahre Dir die Disziplin, alle Ausnahmen zu kommentieren: warum sie existieren, wer sie braucht, wann Du sie das letzte Mal überprüft hast. Ausnahmen sind kein Makel – aber unkommentierte Ausnahmen sind technischer Schuldenaufbau.
Fazit: Klarheit ist die beste Härtung
Diese Baseline hat ein einfaches Ziel: Klarheit vor Komplexität. Du bekommst eine OpenBSD‑Firewall, die im Alltag berechenbar bleibt, die Angriffsfläche klein hält und Dir über Labels, Tabellen und sinnvolle Defaults jederzeit zeigt, was tatsächlich passiert. Wir setzen auf explizite Entscheidungen statt auf implizite Nebenwirkungen: strenge Egress‑Politik, DNS‑Erzwingung auf definierte Resolver, keine stillen Nebenkanäle über QUIC oder DoH/DoT/DoQ, deterministische States und robuste Kernel‑Schalter. Das Ergebnis ist kein akademisches Kunststück, sondern eine belastbare Ausgangsbasis, auf der Du ohne Bauchschmerzen weiterbauen kannst.
Wichtig ist, dass diese Baseline bewusst keinen lokalen Resolver und keinen lokalen NTP‑Dienst voraussetzt. Sie richtet sich an Setups, die schnell stabil laufen sollen, ohne dass Du zusätzliche Infrastruktur aufziehen musst. Wenn Du später mehr Kontrolle im eigenen Netz möchtest, lässt sich das nahtlos ergänzen – die Architektur ist darauf vorbereitet, ohne dass Du die Grundhaltung aufgeben musst.
Damit Du nicht lange suchen musst: Die vollständigen Konfigurationsvorschläge findest Du weiter unten – sowohl die pf.conf in zwei Profilen (Router‑Only ohne DMZ und Router+DMZ mit strikter Kapselung) als auch die gehärtete sysctl.conf. Der Artikel hier erklärt die Entscheidungen; die Dateien unten setzen sie 1:1 um. Wenn Du Dich an die Reihenfolge „prüfen → laden → messen“ hältst, kommst Du schnell zu einem reproduzierbaren Ergebnis.
Ebenso wichtig ist die Ehrlichkeit über den Scope: Nicht im Fokus dieser Baseline sind hochspezialisierte Zielangriffe oder vollumfängliche IDS/IPS‑Szenarien. Das heißt nicht, dass Du darauf verzichten musst – im Gegenteil. Diese Basis ist so gelegt, dass Du solche Bausteine geordnet ergänzen kannst. Drei typische Erweiterungswege haben sich in der Praxis bewährt.
Wenn Du beim Lesen Ideen hattest, wie sich einzelne Regeln noch schärfen lassen, wenn Du besondere Anforderungen hast oder wenn Du Beobachtungen aus Deinem Betrieb teilen möchtest: Melde Dich gern. Real‑World‑Rückmeldungen sind der beste Katalysator für sinnvolle Verbesserungen – und fließen in künftige Ergänzungen ein. Sicherheit ist ein Prozess, kein Sprint; mit einer klaren Baseline im Rücken und einer Community, die Erfahrungen teilt, wird aus „gut“ schnell „sehr gut“.
Download sysctl.conf: https://www.protectstar.com/download/blog/sysctl.txt
Download pf.conf (with DMZ): https://www.protectstar.com/download/blog/pf.conf_withDMZ.txt
Download pf.conf (no DMZ): https://www.protectstar.com/download/blog/pf.conf_noDMZ.txt