← Übersicht  ·  Skripte & Dateien  ·  cloud-host · OpenShift · Betrieb

NetworkPolicy in OpenShift

Hier spielst du NetworkPolicy von Hand durch: ab Werk darf jeder Pod jeden erreichen – eine NetworkPolicy schaltet das ab, du siehst den Traffic wirklich brechen, und erlaubst gezielt wieder. Plus die zwei Fallen, die jedem passieren. EX280-relevant.

Stand: 4. September 2026 OKD 4.x / OCP 4.x ns library

Voraussetzung: ein Cluster mit oc login, Namespace library mit mindestens zwei laufenden Pods (z. B. catalog-service und api-gateway). Alles hier wirkt sofort, ohne Pod-Neustart – OVN (F1) erzwingt die Regeln direkt.

Ab Werk darf jeder Pod jeden Pod erreichen, clusterweit. Eine NetworkPolicy, die eine Pod-Menge auswählt, schaltet genau diese Pods auf default-deny für die genannte Richtung – danach erlaubst du gezielt einzelne Verbindungen wieder. Zeichnung aus dem OpenShift-Atlas F2, auf den library-Namespace bezogen.

Ohne Policy: alles offen. Mit Policy: die ausgewählten Pods sind zu, bis du öffnest. Ausgangslage: default-allow ein frischer Namespace hat keine NetworkPolicy → jeder Pod erreicht jeden Pod, clusterweit auch aus anderen Namespaces ein kompromittierter Pod kann alles scannen Isolation ist nicht automatisch (A2) Namespace = RBAC- und Quota-Grenze, aber keine Netz-Grenze die Netz-Trennung kommt separat – hier Bibliothek: heißt, DB und Kafka sind erstmal von jedem Pod erreichbar eine NetworkPolicy wählt aus und schließt spec.podSelector: {matchLabels: {app: catalog-service}} nur die catalog-service-Pods sind betroffen policyTypes: [Ingress] und/oder [Egress] → diese Richtung wird default-deny für diese Pods dann Regeln, die wieder erlauben: ingress: [{from: [{podSelector: {app: api-gateway}}], ports: [{port: 8080}]}] Selektoren: podSelector, namespaceSelector (mit and kombiniert), ipBlock (CIDR + except), ports mehrere Policies auf denselben Pods: die Erlaubnisse summieren sich es gibt kein Deny in einer NetworkPolicy – nur Auswahl + Allow (wie RBAC, A5) AdminNetworkPolicy (clusterweit, vor den Namespace-Policies) kann hart verbieten Bibliothek: der Plan 1 · deny-all-ingress im Namespace library (leerer podSelector: {}, policyTypes: [Ingress]) 2 · api-gateway, library-frontend: Ingress nur aus openshift-ingress (der Router, B4) 3 · die 6 internen Dienste: Ingress nur aus api-gateway 4 · Postgres, Redis, Kafka: nur aus ihren Konsumenten 5 · Egress überall auf openshift-dns erlauben Ergebnis: die DB ist nur noch von den Diensten erreichbar, die sie wirklich brauchen liefert das Helm-Chart mit (B11) – ein NetworkPolicy-Manifest je Dienst die Fallen 1 · DNS vergessen: eine Egress-Policy ohne Regel für openshift-dns (UDP/TCP 53) → die Namensauflösung bricht, alles läuft in Timeouts 2 · Ingress-Policy ohne Deny-Basis: eine reine Allow-Policy schließt nichts – erst eine Policy, die den Pod auswählt, macht ihn default-deny 3 · namespaceSelector braucht ein Label am Quell-Namespace – nicht jeder hat eins 4 · Health-Probes (B5) kommen vom kubelet, nicht von einem Pod – separat erlauben nachsehen & testen oc get netpol -n library oc describe netpol deny-all-ingress -n library testen: aus einem Pod oc rsh und curl gegen das Ziel wirkt sofort (OVN, F1) – kein Pod-Neustart nötig AdminNetworkPolicy: oc get anp (clusterweit) Console: Netzwerk-Ansicht zeigt die erlaubten Verbindungen als Graph Merksatz: eine Policy, die einen Pod auswählt, macht ihn für die genannte Richtung default-deny – danach zählt nur, was du erlaubst kein Deny in einer NetworkPolicy – für hartes Verbieten über Namespaces hinweg: AdminNetworkPolicy OCP-Unterschied: NetworkPolicy ist reines Kubernetes, OVN setzt sie um – EgressFirewall (Ziel-Regeln je Namespace) und AdminNetworkPolicy sind die OpenShift-/OVN-Erweiterungen.
Auswahl macht zu, Regeln machen auf. Ohne NetworkPolicy erreicht jeder Pod jeden – ein Namespace ist keine Netz-Grenze (ein Namespace). Eine Policy, die per podSelector eine Pod-Menge auswählt, schaltet genau diese Pods für die in policyTypes genannte Richtung auf default-deny; die ingress/egress-Regeln erlauben dann gezielt wieder. Es gibt kein Deny – mehrere Policies summieren ihre Erlaubnisse. Klassische Falle: die DNS-Egress-Regel vergessen, dann bricht die Namensauflösung.
  • ab Werk gilt default-allow: jeder Pod erreicht jeden Pod clusterweit – ein frischer Namespace ist offen
  • ein Namespace ist eine RBAC- und Quota-Grenze, aber keine Netz-Grenze – die kommt separat mit NetworkPolicy
  • eine Policy, die per podSelector eine Pod-Menge auswählt, schaltet genau diese Pods auf default-deny für die Richtungen in policyTypes (Ingress, Egress)
  • danach fügt man ingress/egress-Regeln hinzu, die bestimmten Verkehr wieder erlauben
  • Selektoren: podSelector, namespaceSelector, ipBlock (CIDR + except), ports
  • es gibt kein Deny in einer NetworkPolicy – nur Auswahl und Allow, und mehrere Policies auf denselben Pods summieren ihre Erlaubnisse (wie bei RBAC)
  • OVN (F1) erzwingt die Regeln – sie wirken sofort, ohne Pod-Neustart
  • AdminNetworkPolicy / BaselineAdminNetworkPolicy: clusterweit, admin-owned, werden vor den Namespace-Policies ausgewertet und können hart verbieten
  • Falle DNS: eine Egress-Policy ohne Regel für openshift-dns (Port 53) → die Namensauflösung bricht, alles läuft in Timeouts
  • Falle Probes: Health-Probes (Probes) kommen vom kubelet, nicht von einem Pod – separat erlauben
  • Bibliothek: eine deny-all-ingress-Basis in library, dann Ingress für api-gateway und library-frontend nur aus openshift-ingress, für die 6 internen Dienste nur aus api-gateway, Postgres und Kafka nur aus ihren Konsumenten
  • nachsehen: oc get netpol -n library, oc describe netpol deny-all-ingress -n library, testen mit oc rsh deploy/api-gateway -n library plus curl
  • OCP-Unterschied: NetworkPolicy ist reines Kubernetes – EgressFirewall und AdminNetworkPolicy sind die OVN-Erweiterungen

1 Default-allow, live

Ab Werk gilt default-allow: jeder Pod erreicht jeden Pod, clusterweit. Ein Namespace ist eine RBAC- und Quota-Grenze (A2), aber keine Netz-Grenze.

Laptop · Bash
# von einem Pod aus einen anderen Pod erreichen - geht ab Werk:
oc rsh -n library deploy/api-gateway curl -s -o /dev/null -w '%{http_code}\n' \
  http://catalog-service:8080/actuator/health

# es gibt noch keine einzige Policy:
oc get netpol -n library

Eine NetworkPolicy, die per podSelector eine Pod-Menge auswählt, schaltet genau diese Pods auf default-deny – aber nur für die Richtungen (ingress/egress), die sie überhaupt nennt. Eine Policy ohne egress-Block ändert am Egress nichts.

2 deny-all-ingress anlegen

Jetzt brechen wir den Traffic wirklich – und sehen es.

Laptop · Bash
cat <<'YAML' | oc apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: library
spec:
  podSelector: {}
  policyTypes: [Ingress]
YAML

# derselbe Aufruf wie eben - jetzt bricht er:
oc rsh -n library deploy/api-gateway curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 \
  http://catalog-service:8080/actuator/health
# Timeout oder Connection refused - sofort, kein Pod-Neustart noetig

podSelector: {} (leer) wählt alle Pods im Namespace. policyTypes: [Ingress] begrenzt die Wirkung auf eingehenden Verkehr – Egress bleibt unangetastet.

3 Gezielt wieder erlauben

Laptop · Bash
cat <<'YAML' | oc apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-api-gateway
  namespace: library
spec:
  podSelector:
    matchLabels: { app: catalog-service }
  policyTypes: [Ingress]
  ingress:
  - from:
    - podSelector:
        matchLabels: { app: api-gateway }
    ports:
    - port: 8080
YAML

oc rsh -n library deploy/api-gateway curl -s -o /dev/null -w '%{http_code}\n' \
  http://catalog-service:8080/actuator/health
# 200 - api-gateway darf wieder rein. Jeder ANDERE Pod bleibt draussen

Zwei Policies auf demselben Pod (deny-all-ingress wählt ihn per podSelector: {} mit) – sie summieren sich, dazu mehr in Schritt 5.

4 Die Selektoren

Selektorwählt
podSelectorPods per Label, im eigenen Namespace
namespaceSelectoralle Pods in Namespaces mit passendem Label – für Verkehr zwischen Namespaces
podSelector + namespaceSelector zusammennur Pods mit beiden Labels (UND-Verknüpfung), im genannten Namespace
ipBlockein CIDR-Bereich, optional mit except – für Verkehr von/zu außerhalb des Clusters
portsschränkt zusätzlich auf bestimmte Ports/Protokolle ein
Beispiel: aus jedem Namespace mit Label
  ingress:
  - from:
    - namespaceSelector:
        matchLabels: { network.openshift.io/policy-group: ingress }   # der Router-Namespace

5 Mehrere Policies summieren

Es gibt kein deny in einer NetworkPolicy – nur Auswahl und Allow.

1 Policywählt sie einen Pod aus, schaltet er für die genannte Richtung auf default-deny
mehrere Policiestreffen mehrere Policies denselben Pod, gilt die Vereinigung aller ingress/egress-Regeln – nie eine schränkt eine andere ein
AdminNetworkPolicyclusterweit, admin-owned, OVN-Erweiterung – wird vor den Namespace-Policies ausgewertet und kann explizit verbieten (Deny-Aktion), anders als die normale NetworkPolicy

Praktisch: eine breite deny-all-ingress plus mehrere kleine, gezielte allow-from-<dienst>-Policies ist der übliche Aufbau – nie eine einzige riesige Policy pflegen.

6 Zwei Fallen: DNS und Probes

FalleSymptomFix
DNSeine Egress-Policy ohne Regel für openshift-dns (Port 53) – die Namensauflösung bricht, alles läuft in Timeouts, nicht nur der gemeinte VerkehrEgress-Policies bekommen immer eine Ausnahme für DNS mit
ProbesHealth-Probes (B5) kommen vom kubelet, nicht von einem Pod – ein zu enges podSelector in der from-Liste blockt sie, der Pod geht auf NotReadyProbes brauchen keine extra Regel (sie laufen node-lokal), aber prüfen: kommt der Traffic wirklich von einem „Pod“ oder vom Node selbst
Laptop · Bash · DNS-Ausnahme
cat <<'YAML' | oc apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: library
spec:
  podSelector: {}
  policyTypes: [Egress]
  egress:
  - to:
    - namespaceSelector: {}
    ports:
    - { protocol: UDP, port: 53 }
    - { protocol: TCP, port: 53 }
YAML

7 Egress-Policy

Genau umgekehrt: nur den Traffic raus einschränken, Ingress bleibt offen.

Laptop · Bash
# testen: kann catalog-service gerade irgendwohin raus?
oc rsh -n library deploy/catalog-service curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 \
  http://api-gateway:8080/actuator/health

# Egress auf nur Postgres + DNS begrenzen (DNS-Ausnahme aus Schritt 6 vorausgesetzt):
cat <<'YAML' | oc apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: catalog-egress-db-only
  namespace: library
spec:
  podSelector:
    matchLabels: { app: catalog-service }
  policyTypes: [Egress]
  egress:
  - to:
    - podSelector:
        matchLabels: { app.kubernetes.io/name: postgresql }
    ports:
    - { port: 5432 }
YAML
# jetzt bricht der Aufruf zu api-gateway - Egress ist jetzt auf Postgres beschraenkt

Egress-Policies sind seltener als Ingress-Policies (das Risiko liegt meist im Reinkommen), aber genau richtig für einen Dienst, der nur zu seiner eigenen DB darf und sonst nirgendwohin – ein kompromittierter Pod kann dann nicht querschlagen.

8 Wie die Bibliothek es macht

PolicyWirkung
deny-all-ingressBasis im Namespace library – ab hier ist alles zu
allow-from-routerIngress für api-gateway und library-frontend nur aus openshift-ingress (der Router-Namespace, B4) – die einzigen zwei Dienste mit einer Route
allow-internaldie 8 Spring-Dienste + Bitnami-Infra reden untereinander über podSelector auf gemeinsame Labels – kein Dienst ist von außen direkt erreichbar

Ergebnis: nur zwei Dienste haben überhaupt einen Weg von außen (plus Keycloak über seine eigene Route, B4) – die sechs restlichen Fachdienste sind nur clusterintern erreichbar, selbst wenn ihre Route aus Versehen angelegt würde, würde die NetworkPolicy den Zugriff trotzdem blocken.

9 Nachschauen

Befehlzeigt
oc get netpol -n librarywelche Policies existieren
oc describe netpol deny-all-ingress -n librarySelektor + Regeln im Klartext
oc rsh deploy/<dienst> -n library + curlder einzige verlässliche Test – von einem echten Pod aus prüfen, nicht vom Laptop

Web-Konsole: Networking → NetworkPolicies zeigt eine Liste, aber keine Simulation – ob eine Verbindung wirklich durchkommt, testet man immer live aus einem Pod.

+ Die Kurzfassung

Vorgabedefault-allow, clusterweit – ein Namespace ist keine Netz-Grenze
eine Policywählt Pods per podSelector, schaltet sie für die genannte Richtung auf default-deny
mehrere Policiessummieren sich – nie deny, nur Vereinigung von Allow
zwei FallenDNS-Egress vergessen (alles bricht) · Probes kommen vom kubelet, nicht von einem Pod
⌂ Cockpit