Network Security for CKS¶
π Network Policies - NetworkPolicy specification and behavior
NetworkPolicy Fundamentals¶
How NetworkPolicies Work¶
- NetworkPolicies are namespace-scoped resources
- They select pods using label selectors
- They define allowed ingress and/or egress rules
- If no NetworkPolicy selects a pod, all traffic is allowed (default allow)
- Once any NetworkPolicy selects a pod, only explicitly allowed traffic is permitted
- A CNI plugin that supports NetworkPolicy is required (Calico, Cilium, Weave Net)
π Declare Network Policy - Tutorial for creating NetworkPolicies
NetworkPolicy Specification¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: example-policy
namespace: production
spec:
podSelector: # Which pods this policy applies to
matchLabels:
app: web
policyTypes: # Which traffic directions are controlled
- Ingress
- Egress
ingress: # Allowed inbound traffic
- from:
- podSelector: # Pods in same namespace
matchLabels:
role: frontend
- namespaceSelector: # Pods in specific namespaces
matchLabels:
env: production
ports:
- protocol: TCP
port: 80
egress: # Allowed outbound traffic
- to:
- podSelector:
matchLabels:
role: database
ports:
- protocol: TCP
port: 5432
Selector Types¶
podSelector - Select pods by labels within the same namespace:
from:
- podSelector:
matchLabels:
app: frontend
namespaceSelector - Select all pods in namespaces matching labels:
from:
- namespaceSelector:
matchLabels:
env: production
Combined (AND logic) - Pods matching labels IN namespaces matching labels:
from:
- namespaceSelector:
matchLabels:
env: production
podSelector:
matchLabels:
app: frontend
Separate entries (OR logic) - Pods matching labels OR namespaces matching labels:
from:
- namespaceSelector:
matchLabels:
env: production
- podSelector:
matchLabels:
app: frontend
Important: The difference between AND and OR is a single dash (-). AND has one dash before the first selector; OR has a dash before each selector. This is a common exam trap.
ipBlock Selector¶
from:
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24
Common NetworkPolicy Patterns¶
Default Deny All Ingress¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
Default Deny All Egress¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
Default Deny All Traffic (Ingress + Egress)¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Allow DNS Egress (Critical for most policies)¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
Allow Intra-Namespace Communication¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {}
Allow Monitoring Namespace Access¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- port: 9090
protocol: TCP
Blocking Cloud Metadata Access¶
Cloud provider metadata endpoints (169.254.169.254) can expose sensitive information including IAM credentials. Block access with a NetworkPolicy:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: block-metadata
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.169.254/32
Ingress Security¶
π Ingress - Ingress resource documentation π Ingress Controllers - Available Ingress controller implementations
TLS Configuration¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
tls:
- hosts:
- app.example.com
secretName: tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Creating TLS Secrets¶
# Create TLS secret from certificate and key files
kubectl create secret tls tls-secret \
--cert=tls.crt \
--key=tls.key \
-n production
# Generate self-signed certificate for testing
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=app.example.com"
Network Segmentation Best Practices¶
Multi-Tier Application Isolation¶
- Default deny all traffic in the namespace
- Allow DNS egress for name resolution
- Frontend pods - Allow ingress from Ingress controller, egress to backend
- Backend pods - Allow ingress from frontend, egress to database
- Database pods - Allow ingress from backend only, deny all egress
Namespace Isolation Strategy¶
- Label namespaces consistently (environment, team, tier)
- Use namespace selectors for cross-namespace policies
- Create default-deny policies in every namespace
- Allow only required cross-namespace communication
- Block metadata endpoint access in all namespaces
Testing NetworkPolicies¶
Verification Commands¶
# List NetworkPolicies in a namespace
kubectl get networkpolicy -n production
# Describe policy details
kubectl describe networkpolicy default-deny-all -n production
# Test connectivity from a debug pod
kubectl run test-pod --image=busybox --rm -it --restart=Never -n production -- wget -qO- --timeout=2 http://web-service.production.svc:80
# Test cross-namespace connectivity
kubectl run test-pod --image=busybox --rm -it --restart=Never -n staging -- wget -qO- --timeout=2 http://web-service.production.svc:80
# Test DNS resolution
kubectl run test-pod --image=busybox --rm -it --restart=Never -n production -- nslookup kubernetes.default.svc
Key Takeaways¶
- Default Deny - Always start with default-deny policies in production namespaces
- DNS Egress - Always allow DNS (port 53 UDP/TCP) when using egress policies
- AND vs OR - Understand the YAML structure difference between combined selectors (AND) and separate selectors (OR)
- CNI Support - NetworkPolicies require a CNI that supports them (Calico, Cilium)
- Metadata Blocking - Block cloud metadata endpoint (169.254.169.254) access
- Testing - Always verify policies work by testing connectivity from relevant pods
- policyTypes - Only listed policy types are enforced; if you omit Egress from policyTypes, egress is not affected