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.
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.
# 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.
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
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
| Selektor | wählt |
|---|---|
podSelector | Pods per Label, im eigenen Namespace |
namespaceSelector | alle Pods in Namespaces mit passendem Label – für Verkehr zwischen Namespaces |
podSelector + namespaceSelector zusammen | nur Pods mit beiden Labels (UND-Verknüpfung), im genannten Namespace |
ipBlock | ein CIDR-Bereich, optional mit except – für Verkehr von/zu ausserhalb des Clusters |
ports | schränkt zusätzlich auf bestimmte Ports/Protokolle ein |
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.
ingress/egress-Regeln – nie eine schränkt eine andere einDeny-Aktion), anders als die normale NetworkPolicyPraktisch: 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
| Falle | Symptom | Fix |
|---|---|---|
| DNS | eine Egress-Policy ohne Regel für openshift-dns (Port 53) – die Namensauflösung bricht, alles läuft in Timeouts, nicht nur der gemeinte Verkehr | Egress-Policies bekommen immer eine Ausnahme für DNS mit |
| Probes | Health-Probes (B5) kommen vom kubelet, nicht von einem Pod – ein zu enges podSelector in der from-Liste blockt sie, der Pod geht auf NotReady | Probes brauchen keine extra Regel (sie laufen node-lokal), aber prüfen: kommt der Traffic wirklich von einem „Pod“ oder vom Node selbst |
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.
# 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
| Policy | Wirkung |
|---|---|
deny-all-ingress | Basis im Namespace library – ab hier ist alles zu |
allow-from-router | Ingress für api-gateway und library-frontend nur aus openshift-ingress (der Router-Namespace, B4) – die einzigen zwei Dienste mit einer Route |
allow-internal | die 8 Spring-Dienste + Bitnami-Infra reden untereinander über podSelector auf gemeinsame Labels – kein Dienst ist von aussen direkt erreichbar |
Ergebnis: nur zwei Dienste haben überhaupt einen Weg von aussen (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
| Befehl | zeigt |
|---|---|
oc get netpol -n library | welche Policies existieren |
oc describe netpol deny-all-ingress -n library | Selektor + Regeln im Klartext |
oc rsh deploy/<dienst> -n library + curl | der 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
podSelector, schaltet sie für die genannte Richtung auf default-denydeny, nur Vereinigung von Allow