Kein Land für alte Pakete
Was alle „wissen“: Das Netzwerk abzuriegeln ist kostenlose Sicherheit. Den gesamten ausgehenden Traffic standardmäßig blockieren und nur das erlauben, was wirklich benötigt wird. Nur Vorteile – was soll schon dagegen sprechen, vorsichtig zu sein?
Was tatsächlich passiert: „Default Deny“ ist eine Sicherheitsstrategie, kein Kontrollkästchen – und sie versagt nach dem Prinzip „geschlossen und lautlos“. Eine einzige vergessene Allow-Regel löst keinen Fehler aus. Stattdessen hängt ein Pod, wird anschließend beendet und sieht dann wie ein völlig anderer Absturz aus. Teams verbringen Wochen damit, dem falschen Phantom hinterherzujagen.
Teil einer kleinen Serie für alle, die zusehen, wie KI alles verschlingt, und dabei lernen, dass die am sichersten klingende Einstellung eine Plattform unbemerkt lahmlegen kann. Der Titel ist eine Anspielung auf die Coen-Brüder – ein stiller, unerbittlicher Killer und jede Menge Pakete, die nirgendwo mehr hinkommen.
Der Glaube: Alles verbieten, besser schlafen
Der Ratschlag ist überall zu finden und grundsätzlich nicht falsch: Pods sollten nicht mit dem gesamten Internet kommunizieren dürfen. Setze den Standard auf Deny und erlaube anschließend nur die konkreten Ziele, die jeder Dienst benötigt. Ein kompromittierter Container kann nicht nach Hause telefonieren, wenn er nirgendwohin gelangen kann.
flowchart LRPod[Your pod] -->|"allow only DNS"| World[Everything else: ❌ denied]style World fill:#d1fae5,stroke:#10b981

Auf der Präsentationsfolie ist das ein voller Erfolg. Ein kleinerer Wirkungsradius bei Sicherheitsvorfällen, zufriedenere Auditoren, scheinbar keinerlei Kosten. Also führst du die Regel in all deinen Namespaces ein und machst weiter – mit dem guten Gefühl, verantwortungsvoll gehandelt zu haben.
Die Kosten sind real. Sie treten nur verzögert auf und tarnen sich. Denn an dem Tag, an dem du diesen Standard umstellst, unterwirfst du stillschweigend jeden Pod einer Regel, von der er nichts weiß. Und wenn die Fehler auftreten, werden sie nicht wie Netzwerkfehler aussehen.
Die Realität: Jetzt braucht alles einen Passierschein
Was bedeutet „standardmäßig blockieren“ in der Praxis tatsächlich? Ein gewöhnlicher Pod kommuniziert nicht nur mit deiner Anwendung. Er greift ständig auf überraschend viele andere Ziele zu, nur um überhaupt funktionieren zu können:
flowchart TBPod[A perfectly normal pod]Pod --> D[DNS — to resolve any name at all]Pod --> A[The cluster's API — operators, controllers]Pod --> S[Object storage / external APIs]Pod --> DB[The database / cache]style Pod fill:#cfe8ff,stroke:#3b82f6

Jede einzelne dieser Verbindungen benötigt jetzt eine eigene, explizite Allow-Regel. Fehlt auch nur eine einzige, ist der Pod kaputt – nicht „weniger sicher“, sondern kaputt. Der Metrikensammler erreicht die API nicht, um herauszufinden, welche Ziele er überwachen soll. Der Operator kann die von ihm verwalteten Ressourcen nicht lesen. Die Anwendung erreicht ihre eigene Datenbank nicht.
Und keiner dieser Dienste erhält eine höfliche Meldung wie „Verbindung verweigert“. Denn Default Deny verweigert die Verbindung nicht aktiv – die Pakete werden ins Leere verworfen, während der aufrufende Dienst einfach weiter wartet.
Sicherheitsmaßnahmen haben einen Wirkungsradius, und der ausgehende Traffic unter Default Deny hat einen großen. Das Problem ist nicht die Idee selbst. Das Problem ist, dass aus „Ich habe eine Konfigurationszeile vergessen“ plötzlich „Ein Dienst ist auf mysteriöse Weise tot“ wird – ohne Fehlermeldung, nach der du in den Logs suchen könntest.
Der Tatort: 32 Sekunden
Das ist das Detail, das diese Geschichte erzählenswert macht, denn genau hier entsteht die Fehldiagnose. Ein Pod, der ein Ziel nicht erreichen kann, schlägt nicht sofort fehl. Er hängt – geduldig wartend auf eine Verbindung, die niemals antworten wird –, bis ein Timeout eintritt.
Jetzt kommt eine Health-Probe hinzu, die den Pod beendet, wenn er beispielsweise innerhalb von 30 Sekunden nicht reagiert. Beobachte den zeitlichen Ablauf:
sequenceDiagramparticipant P as Podparticipant Net as (blocked network)participant Probe as Health probe (30s patience)P->>Net: connect to the API...Note over P,Net: silence. packets dropped. pod waits.Probe->>P: 30s up. Unresponsive. Killed. 💀Note over P: ...and at ~32s, the REAL error<br/>would have been logged —<br/>but the pod's already dead.

Der Pod wird nach 30 Sekunden beendet, zwei Sekunden bevor er den eigentlichen Fehler „Netzwerk nicht erreichbar“ protokolliert hätte. Bei jedem Neustart siehst du deshalb dasselbe Bild: Der Pod startet, gibt zwei unspektakuläre Setup-Zeilen aus und stirbt – ohne Fehlermeldung.
Das sieht genau aus wie ein Absturz, ein durch Speichermangel ausgelöster Kill oder ein fehlerhaftes Container-Image. Es sieht nach allem aus, nur nicht nach dem tatsächlichen Problem: einer fehlenden Firewall-Regel, deren Timing perfekt darauf abgestimmt ist, die eigenen Beweise zu verbergen. Teams jagen diesem Phantom wochenlang hinterher.
🤓 Für die Technik-Nerds unter euch: Der Pod wird normalerweise durch eine Liveness-Probe beendet, deren anfängliche Verzögerung 0 Sekunden beträgt und die mit einem Verbindungs-Timeout von etwa 32 Sekunden konkurriert.
Die Lösung ist eine zusätzliche Egress-Regel. Doch hier lauert die zweite Falle: Bei einem modernen CNI wie Cilium greift eine gewöhnliche Kubernetes-
NetworkPolicymit einemipBlock-CIDR für den API-Server möglicherweise stillschweigend nicht. Der Grund: Der Traffic zwischen Nodes und API-Servern wird über spezielle Identitäten wieremote-nodeundkube-apiserverklassifiziert, nicht einfach über eine routbare IP-Adresse.Du musst deshalb die eigenen Entity-Selektoren des CNI verwenden, beispielsweise
toEntities: [kube-apiserver], sowietoFQDNsfür den Objektspeicher.Das bedeutet: Selbst dein Versuch, das Problem zu beheben, kann wirkungslos bleiben – ohne eine einzige Fehlermeldung. Bis ganz nach unten gilt: geschlossen, koste es, was es wolle.
Warum sich dieser Fehler so gut versteckt
Betrachten wir alle Faktoren, die gegen dich arbeiten. Dann wird klar, warum dich dieses Problem wochenlang beschäftigen kann:
flowchart LRM[Missing allow-rule] --> H[Pod hangs, doesn't error]H --> K[Probe kills it before it logs why]K --> L["Looks like a crash, not a network issue"]L --> F["Your fix silently no-ops<br/>(wrong rule type for the CNI)"]style L fill:#fee2e2,stroke:#ef4444style F fill:#fee2e2,stroke:#ef4444

Vier voneinander unabhängige Faktoren spielen zusammen: Der Fehler bleibt unsichtbar, das Symptom wird falsch eingeordnet, die Beweise werden durch genau die Probe vernichtet, die eigentlich helfen soll, und selbst die naheliegende Lösung kann unbemerkt wirkungslos bleiben.
Keiner dieser Faktoren ist ein Fehler der Grundidee. Sie alle sind die Kosten dafür, eine Sicherheitsstrategie wie ein bloßes Kontrollkästchen zu behandeln.
Wie du Default Deny einsetzt, ohne eine Woche zu verlieren
Default Deny ist weiterhin eine gute Sicherheitsmaßnahme. Der entscheidende Punkt ist, es als ein System zu behandeln, das du aktiv betreibst – und nicht als einen Schalter, den du einfach umlegst:
Erlaube zuerst überall die unscheinbaren, aber unverzichtbaren Verbindungen. Bevor du etwas anderes tust, richte Allow-Regeln für DNS, die Cluster-API und deine Datenschicht ein. Die meisten „mysteriösen Abstürze“ lassen sich auf eine dieser drei Komponenten zurückführen.
Behalte deine Probes im Blick. Eine Liveness-Probe ohne anfängliche Verzögerung, die einem Netzwerk-Timeout von 30 Sekunden gegenübersteht, beendet den geduldigen Wartenden, bevor er aussagen kann. Gib Startup-Probes genügend Zeit, damit der tatsächliche Fehler sichtbar wird.
Kenne die Matching-Regeln deines CNI. In einem identitätsbasierten Netzwerk greifen CIDR-Allow-Regeln für Nodes und den API-Server möglicherweise nicht. Verwende stattdessen Entity- und FQDN-Selektoren. Überprüfe anschließend, ob die Regel tatsächlich greift.
Wenn ein Pod ohne Fehlermeldung „abstürzt“, untersuche zuerst das Netzwerk und erst danach die Anwendung. Stille, fehlende Logs und ein Abbruch nach einer festen Zeitspanne sind typische Anzeichen für eine verworfene Verbindung – nicht unbedingt für einen Fehler in deinem Code.
Ja, aber – ist die Alternative, alles zu erlauben, nicht noch schlimmer?
Ein berechtigter Einwand: Default Deny hat diese Probleme nicht erfunden, und uneingeschränkter Zugriff ist tatsächlich weniger sicher. Die falsche Schlussfolgerung wäre also: „Dann sollte man den ausgehenden Traffic eben nicht einschränken.“
Die Sicherheitsstrategie ist richtig. Das eigentliche Problem liegt woanders.
Es ist der lautlose Fehler, der falsch interpretiert wird. Eine verworfene Verbindung, die den Dienst warten lässt, dessen Pod beendet wird, bevor er den Fehler protokollieren kann, und die anschließend wie ein Absturz aussieht – das kostet dich Wochen, nicht die Sicherheitsmaßnahme selbst.
Behalte Default Deny bei. Sorge aber dafür, dass Fehler unüberhörbar werden: durch Startup-Probes, die den tatsächlichen Fehler sichtbar werden lassen, durch Allow-Listen für die unverzichtbaren Verbindungen von Anfang an und durch Prüfungen, die sicherstellen, dass deine Regeln tatsächlich greifen – insbesondere bei identitätsbasierten CNIs.
Default Deny ist nicht die Falle. Die Falle ist Default Deny, das lautlos versagt.
Die wichtigsten Erkenntnisse
„Kostenlose Sicherheit“ ist nicht kostenlos – die Kosten werden nur aufgeschoben und verschleiert. Default Deny für ausgehenden Traffic ersetzt einen sofort erkennbaren Fehler durch ein später auftretendes Rätsel. Das lohnt sich, wenn du auf dieses Rätsel vorbereitet bist.
Es versagt geschlossen und lautlos. Keine aktive Zurückweisung, kein Logeintrag – nur ein hängender Prozess, den eine Health-Probe zwei Sekunden vor dem Auftreten der eigentlichen Fehlermeldung in einen vermeintlichen Absturz verwandelt.
Der Wirkungsradius umfasst alles, wovon ein Pod unbemerkt abhängig ist: DNS, die API, den Speicher und die Datenbank. Jede dieser Verbindungen braucht ihren eigenen Passierschein.
Selbst die Lösung kann wirkungslos bleiben. Bei einem identitätsbasierten CNI greift die intuitiv gewählte CIDR-Regel möglicherweise nicht für das Ziel, das du freigeben möchtest. Prüfe, ob deine Allow-Regel tatsächlich etwas erlaubt.
Der Bösewicht ist die Stille, nicht die Sicherheitsrichtlinie. Behalte Default Deny bei, aber sorge dafür, dass Fehler laut sichtbar werden. Die nächste verworfene Verbindung soll sich bemerkbar machen, statt einen Absturz vorzutäuschen.
Abschließende Gedanken: Türen abzuschließen ist ein guter Rat. Denk nur daran, dass du damit auch die Türen verriegelt hast, durch die deine eigenen Pods täglich gehen müssen, um ihre Arbeit zu erledigen.
Und wenn einer von ihnen draußen stecken bleibt, wird er nicht gegen die Scheibe klopfen. Er wird still davorstehen, bis etwas seinem Leiden ein Ende setzt – und dich ratlos zurücklassen, während du dich fragst, warum ein vollkommen funktionierender Dienst scheinbar ohne jeden Grund immer wieder stirbt.
Nächste Beiträge

Von Governance-Befunden zu Governance-Signalen
Erfahren Sie, wie Governance einzelne Erkenntnisse durch die Verknüpfung von Beobachtungen, Reviews, Entscheidungen und Feedback in verwertbare Signale verwandelt.

MFA - Die "Qual der Wahl"
Hardware token or smartphone? This blog explores modern MFA methods, their security strengths, risks, and when each approach is the right choice for different users.

Keycloak × Stripe: Unsichtbares Marktplatz-Onboarding mit ereignisgesteuerter Architektur aufbauen
Erfahren Sie, wie Sie ein nahtloses Marktplatz-Onboarding durch die Integration von Keycloak und Stripe Connect mit reaktivem Kotlin und AMQP aufbauen.