Firewalling at the pod level: controlling traffic flow in Kubernetes.
Without any NetworkPolicy, all pods can talk to all pods across every namespace. A default-deny policy flips this to zero-trust.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
podSelector: {} matches every pod in the namespace. An empty ingress: [] or egress: [] field (or omission) means no traffic is allowed for that direction.Each ingress rule specifies from sources and optional ports.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
- namespaceSelector:
matchLabels:
env: production
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24
ports:
- protocol: TCP
port: 8080
from array is OR'd together. Traffic matching any of the three selectors above is allowed on port 8080.The distinction between AND and OR is one of the trickiest parts of NetworkPolicy.
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
- namespaceSelector:
matchLabels:
env: staging
Allows pods labeled app: frontend in any namespace OR any pod in namespaces labeled env: staging.
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
namespaceSelector:
matchLabels:
env: staging
Allows only pods labeled app: frontend that are also in namespaces labeled env: staging.
-) makes all the difference. Two dashes = two separate items (OR). One dash with both selectors = single item (AND).Egress rules control outbound traffic. A common requirement: allow DNS resolution (port 53) even when egress is otherwise denied.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restricted-egress
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
# Allow DNS
- to: []
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# Allow traffic to the database
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
{{- if .Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
policyTypes:
{{- if .Values.networkPolicy.ingress }}
- Ingress
{{- end }}
{{- if .Values.networkPolicy.egress }}
- Egress
{{- end }}
{{- if .Values.networkPolicy.ingress }}
ingress:
{{- toYaml .Values.networkPolicy.ingress | nindent 4 }}
{{- end }}
{{- if .Values.networkPolicy.egress }}
egress:
{{- toYaml .Values.networkPolicy.egress | nindent 4 }}
{{- end }}
{{- end }}
Corresponding values.yaml:
networkPolicy:
enabled: false
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to: []
ports:
- protocol: UDP
port: 53
# Exec into a pod and curl
kubectl exec -it deploy/frontend \
-- curl -s --max-time 3 \
http://api:8080/health
# Check applied policies
kubectl get netpol -n myns
kubectl describe netpol \
allow-frontend -n myns
# Quick test pod
kubectl run test --rm -it \
--image=busybox:1.36 \
--restart=Never -- \
wget -qO- --timeout=3 \
http://api.myns:8080/health
.Values.networkPolicy.enabledkubectl exec + curl/wget to verify connectivityNext: Lesson 13