Kubernetes Network Policy — izolacja ruchu między podami
Opublikowano: 10 kwietnia 2026 · Kategoria: Bezpieczeństwo / Kubernetes
Domyślny klaster Kubernetes to środowisko z zerową izolacją sieciową — każdy pod może połączyć się z każdym innym. Jeśli atakujący przejmie pod frontendowy, może bezpośrednio odpytywać bazę danych. Network Policy to natywny mechanizm K8s do definiowania reguł ruchu sieciowego na poziomie podów i namespace'ów. W tym artykule wdrożymy model least-privilege od podstaw: deny-all baseline, a następnie selektywne zezwalanie na konkretne połączenia.
Wymaganie: CNI plugin obsługujący Network Policy
Network Policy to tylko manifest YAML — egzekwowanie reguł leży po stronie CNI pluginu. Kubernetes nie egzekwuje ich sam. Sprawdź czy Twój klaster ma odpowiedni CNI:
| CNI Plugin | Network Policy | L7 Policies | Wydajność | Instalacja |
|---|---|---|---|---|
| Calico | Tak (iptables / eBPF) | Nie (L3/L4) | Dobra | Łatwa |
| Cilium | Tak (eBPF) | Tak (HTTP/gRPC) | Bardzo dobra | Średnia |
| Weave Net | Tak | Nie | Średnia | Łatwa |
| Flannel | Nie | Nie | Dobra | Bardzo łatwa |
| kindnet (kind) | Tak (od v1.29) | Nie | Dev only | Automatyczna |
# Instalacja Calico (dla kubeadm, bez overlay) kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml # Instalacja Cilium (przez Helm — zalecane) helm repo add cilium https://helm.cilium.io/ helm install cilium cilium/cilium --version 1.15.0 \ --namespace kube-system \ --set hubble.relay.enabled=true \ --set hubble.ui.enabled=true # Weryfikacja kubectl get pods -n kube-system | grep -E 'calico|cilium'
Baseline — deny all ingress i egress
Pierwsza polityka to deny-all dla wszystkich podów w namespace. Pusta lista
ingress: [] i egress: [] blokuje cały ruch. Stosuj ją do każdego namespace
produkcyjnego zanim zaczniesz dodawać wyjątki:
# deny-all.yaml — blokuje caly ruch w namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # pusta selector = dotyczy WSZYSTKICH podow w namespace
policyTypes:
- Ingress
- Egress
ingress: [] # brak wpisow = deny all ingress
egress: [] # brak wpisow = deny all egress
# Uwaga: po zastosowaniu tej polityki pody stracą nawet dostep do DNS!
# Dodaj egress na DNS dla kazdego namespace:
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP Reguły ingress — zezwolenie na konkretne połączenia
# Zezwol frontenowi laczyc sie z backendem
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-allow-from-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: backend # ta polityka dotyczy podow backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # tylko pody z etykieta app=frontend
ports:
- protocol: TCP
port: 8080
---
# Baza danych — tylko backend moze sie laczyc
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-allow-from-backend
namespace: production
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 5432 namespaceSelector — ruch między namespace'ami
# Zezwol Ingress Controllerowi z namespace ingress-nginx dostepu do aplikacji
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-controller
namespace: production
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector: # filtr na namespace
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
podSelector: # + filtr na poda w tym namespace
matchLabels:
app.kubernetes.io/name: ingress-nginx
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443 Uwaga na składnię AND vs OR: podSelector i namespaceSelector w jednym elemencie
listy from to warunek AND (pod MUSI pasować DO OBU). Osobne elementy listy to OR
(pasuje do JEDNEGO lub DRUGIEGO). To częste źródło błędów — sprawdź dokumentację K8s dla tego
rozróżnienia.
Testowanie i debugowanie Network Policy
# Pod testowy z narzędziami sieciowymi kubectl run test-pod -n production --rm -it \ --image=nicolaka/netshoot \ --labels="app=frontend" \ -- bash # W shellu poda testowego: # Sprawdz polaczenie z backendem (powinno dzialac) curl -v http://backend:8080/health # Sprawdz polaczenie z baza (powinno byc zablokowane) nc -zv postgres 5432 # (brak odpowiedzi = timeout = polityka dziala) # Sprawdz DNS nslookup backend.production.svc.cluster.local # Dla Cilium - obserwuj ruch przez Hubble CLI kubectl exec -n kube-system ds/cilium -- cilium monitor --type drop # Sprawdz które NetworkPolicies dotycza poda kubectl get networkpolicies -n production kubectl describe networkpolicy backend-allow-from-frontend -n production