Einführung
Namespaces organisieren Ressourcen, blockieren Netzwerkverkehr jedoch nicht automatisch. NetworkPolicies legen fest, welche ausgewählten Pods Verbindungen aufbauen oder empfangen dürfen, sofern das Netzwerk-Plugin des Clusters diese Richtlinien durchsetzt. Das vorbereitete Calico-Netzwerk unterstützt dies.
Sie werden zunächst nachweisen, dass der Datenverkehr offen ist. Anschließend wenden Sie eine standardmäßige Verweigerung an und erlauben nur einem gekennzeichneten Client aus einem freigegebenen Namespace den Zugriff.
Das Lab folgt einem sicheren Richtlinien-Workflow: Zuerst wird eine funktionierende Ausgangsbasis geschaffen, dann der Datenverkehr blockiert, anschließend die kleinstmögliche erforderliche Ausnahme hinzugefügt und schließlich sowohl ein erlaubter als auch ein verweigerter Zugriff getestet. Wenn nur der erlaubte Client getestet wird, könnte eine zu weit gefasste Richtlinie unbemerkt bleiben.
Server und Clients bereitstellen
Erstellen Sie in diesem Schritt getrennte Namespaces für die Anwendung und die Clients, einen NGINX-Server sowie zwei dauerhaft laufende Clients.
Die Befehle verwenden bewusst vertraute imperative Formen, damit das Netzwerkexperiment nicht durch nebensächliche YAML-Details überlagert wird. Ein Client erhält das Label role=approved, der andere role=untrusted. Der Client-Namespace erhält access=approved. Die späteren Selektoren der Richtlinien verwenden beide Label-Ebenen.
cd /home/labex/project/network-policy
kubectl create namespace practice-apps
kubectl create namespace practice-clients
kubectl label namespace practice-clients access=approved
Erstellen Sie den Server und machen Sie ihn erreichbar. kubectl expose erstellt einen ClusterIP-Service, dessen Selektor mit dem vom Deployment erzeugten Pod-Label app=protected-web übereinstimmt:
kubectl create deployment protected-web -n practice-apps --image=nginx:1.27-alpine --replicas=1
kubectl expose deployment protected-web -n practice-apps --port=80 --target-port=80
Erstellen Sie zwei Diagnose-Client-Pods. Ihre Schleifen mit sleep halten sie für wiederholte kubectl exec-Tests verfügbar:
kubectl run erstellt jeden eigenständigen Pod direkt. --labels weist die Identität zu, anhand derer die Richtlinie den Pod auswählt, --restart=Never verhindert das Erstellen eines Workload-Controllers durch kubectl, und -- trennt die kubectl-Optionen vom Befehl sh -c, der im Container ausgeführt wird. Beim Wait-Befehl bedeutet --all, dass jeder Pod in practice-clients bereit werden muss.
kubectl run approved-client -n practice-clients --image=busybox:1.36 --image-pull-policy=IfNotPresent --labels=role=approved --restart=Never -- sh -c 'while true; do sleep 30; done'
kubectl run untrusted-client -n practice-clients --image=busybox:1.36 --image-pull-policy=IfNotPresent --labels=role=untrusted --restart=Never -- sh -c 'while true; do sleep 30; done'
kubectl wait --for=condition=Ready pod -n practice-clients --all --timeout=120s
kubectl rollout status deployment/protected-web -n practice-apps --timeout=60s
Die Trennung in Namespaces allein erlaubt weiterhin beiden Clients, den Service zu erreichen.
Die Bereitschaftsprüfungen sollten für beide Client-Pods und das Server-Deployment entsprechende Nachweise liefern:
pod/approved-client condition met
pod/untrusted-client condition met
deployment "protected-web" successfully rolled out
An diesem Punkt beschreiben die Labels die Clients, schränken ihren Zugriff jedoch noch nicht ein. Ein Label wird erst dann zu einer Verkehrsregel, wenn ein NetworkPolicy-Selektor es verwendet.
Nachweisen, dass der Datenverkehr zunächst offen ist
Fordern Sie in diesem Schritt den Service aus beiden Clients über Namespace-Grenzen hinweg an. Der vollständig qualifizierte Name enthält den Service- und den Namespace-Namen.
Innerhalb desselben Namespace würde protected-web ausreichen. Aus practice-clients teilt protected-web.practice-apps dem Cluster-DNS sowohl den Namen des Services als auch dessen Namespace mit. Testen Sie beide Clients, bevor Sie eine Richtlinie anwenden, damit ein späterer Fehler eindeutig der Richtlinie und nicht der DNS- oder Service-Konfiguration zugeordnet werden kann.
Wie im Lab zur Gesundheitsprüfung schreibt wget -qO- den Antworttext ohne Fortschrittsanzeige aus. --timeout=3 verhindert, dass eine verweigerte Anfrage unbegrenzt wartet, und die Weiterleitung an grep zeigt nur den charakteristischen NGINX-Text an.
cd /home/labex/project/network-policy
kubectl exec approved-client -n practice-clients -- wget -qO- --timeout=3 http://protected-web.practice-apps | grep 'Welcome to nginx'
kubectl exec untrusted-client -n practice-clients -- wget -qO- --timeout=3 http://protected-web.practice-apps | grep 'Welcome to nginx'
kubectl get networkpolicies -n practice-apps
Ohne eine passende NetworkPolicy ist eingehender Datenverkehr erlaubt. Damit wird der häufige Irrtum korrigiert, dass Namespaces allein Sicherheitsgrenzen für den Netzwerkverkehr darstellen.
Beide Befehle sollten Welcome to nginx finden, und kubectl get networkpolicies sollte keine Ressourcen melden. Dies ist die bekannte funktionierende Ausgangsbasis, die Sie nun bewusst verändern werden.
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
No resources found in practice-apps namespace.
Der wiederholte Seitentext beweist, dass beide Client-Identitäten denselben Service erreichen können, bevor die Isolation beginnt.
Eingehenden Datenverkehr standardmäßig verweigern
Wählen Sie in diesem Schritt jeden Pod in practice-apps aus und erlauben Sie keine Quellen für eingehenden Datenverkehr.
Eine NetworkPolicy wirkt nur für Pods, die von ihr ausgewählt werden, und nur für die in policyTypes angegebene Richtung. Hier wählt podSelector: {} jeden Pod in practice-apps aus. Da keine Regel für erlaubten eingehenden Datenverkehr vorhanden ist, wird dieser standardmäßig verweigert.
cd /home/labex/project/network-policy
cat <<'EOF' > default-deny.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: default-deny-ingress, namespace: practice-apps}
spec:
podSelector: {}
policyTypes: [Ingress]
EOF
kubectl apply -f default-deny.yaml
kubectl exec approved-client -n practice-clients -- wget -qO- --timeout=3 http://protected-web.practice-apps || echo 'blocked as expected'
Ein leerer podSelector wählt jeden Pod im Namespace der Richtlinie aus. Das erwartete Timeout beweist, dass eingehender Datenverkehr nun verweigert wird, nicht dass der Service verschwunden ist.
|| echo ... verarbeitet den erwarteten Rückgabecode ungleich null von wget, damit das Terminal fortgesetzt werden kann. Der Fehler ist in diesem kontrollierten Experiment ein Beleg. Der Server-Pod bleibt bereit; lediglich die Netzwerkzulassung wurde geändert.
networkpolicy.networking.k8s.io/default-deny-ingress created
wget: download timed out
command terminated with exit code 1
blocked as expected
Das Timeout ist zu erwarten, weil ein verweigertes Paket keine Antwort der Anwendung erhält. Die letzte Zeile bestätigt, dass die Shell diesen erwarteten Fehler bewusst in ein verständliches Ergebnis umgewandelt hat.
Einen freigegebenen Client zulassen
Fügen Sie in diesem Schritt eine Freigaberichtlinie hinzu, die sowohl einen freigegebenen Namespace als auch das passende Pod-Label voraussetzt.
NetworkPolicies werden additiv ausgewertet. Die Richtlinie zur standardmäßigen Verweigerung bleibt bestehen, während diese zweite Richtlinie eine einzige erlaubte Quelle ergänzt. Der ausgewählte Server-Pod darf TCP-Port 80 nur dann akzeptieren, wenn sowohl der Quell-Namespace als auch der Quell-Pod übereinstimmen.
cd /home/labex/project/network-policy
cat <<'EOF' > allow-approved.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: allow-approved-client, namespace: practice-apps}
spec:
podSelector: {matchLabels: {app: protected-web}}
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector: {matchLabels: {access: approved}}
podSelector: {matchLabels: {role: approved}}
ports:
- {protocol: TCP, port: 80}
EOF
kubectl apply -f allow-approved.yaml
kubectl exec approved-client -n practice-clients -- wget -qO- --timeout=3 http://protected-web.practice-apps | grep 'Welcome to nginx'
kubectl exec untrusted-client -n practice-clients -- wget -qO- --timeout=3 http://protected-web.practice-apps || echo 'untrusted client blocked'
Da sich die beiden Selektoren im selben from-Eintrag befinden, müssen beide übereinstimmen. Separate Einträge würden eine logische ODER-Verknüpfung bedeuten.
Die Anfrage des freigegebenen Clients sollte wieder erfolgreich sein, während die Anfrage des nicht vertrauenswürdigen Clients weiterhin mit einem Timeout endet. Dieses Ergebnis als Paar beweist, dass die Richtlinie gezielt wirkt und nicht einfach den gesamten eingehenden Datenverkehr wieder freigibt.
networkpolicy.networking.k8s.io/allow-approved-client created
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
wget: download timed out
command terminated with exit code 1
untrusted client blocked
Lesen Sie das Ergebnis als Paar: zuerst der Seiteninhalt für approved-client, anschließend ein Timeout für untrusted-client. Nur die erfolgreiche Anfrage zu sehen, würde nicht beweisen, dass die Regel eng genug gefasst ist.
Zusammenfassung
Sie haben nachgewiesen, dass Namespaces den Datenverkehr standardmäßig nicht isolieren, den eingehenden Datenverkehr standardmäßig verweigert und einem einzigen Client den Zugriff anhand kombinierter Kriterien für Namespace, Pod, Protokoll und Port erlaubt.


