• Default K8s: all pods can talk to all pods
  • Once a NetworkPolicy selects a Pod: only explicitly allowed traffic passes
  • Declarative only: no kubectl create networkpolicy
  • Requires CNI plugin: assume installed on exam

Deny-all ingress + allow specific

# Pattern 1: Deny ALL ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
spec:
  podSelector:
    matchLabels:
      app: db
  policyTypes:
  - Ingress
  # NO ingress rules = deny all ingress
---
# Pattern 2: Allow only from specific pods + namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-webapp
spec:
  podSelector:
    matchLabels:
      app: db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: webapp
      namespaceSelector:
        matchLabels:
          name: production
    ports:
    - protocol: TCP
      port: 5432

Default-deny ALL (ingress + egress)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}         # empty = ALL pods
  policyTypes:
  - Ingress
  - Egress

Egress control

spec:
  podSelector:
    matchLabels:
      app: webapp
  policyTypes:
  - Egress
  egress:
  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP
  - to:
    - podSelector:
        matchLabels:
          app: db

AND vs OR: the key distinction

# SAME item = AND (webapp pod IN prod namespace)
ingress:
- from:
  - podSelector:
      matchLabels:
        app: webapp
    namespaceSelector:
      matchLabels:
        env: prod

# Separate items = OR (webapp pod) OR (any pod in prod namespace)
ingress:
- from:
  - podSelector:
      matchLabels:
        app: webapp
  - namespaceSelector:
      matchLabels:
        env: prod

ipBlock

ingress:
- from:
  - ipBlock:
      cidr: 192.168.1.0/24
      except:
      - 192.168.1.5/32

egress:
- to:
  - ipBlock:
      cidr: 203.0.113.0/24
  ports:
  - protocol: TCP
    port: 443

Allow DNS (required with default-deny egress)

egress:
- to:
  - namespaceSelector:
      matchLabels:
        kubernetes.io/metadata.name: kube-system
    podSelector:
      matchLabels:
        k8s-app: kube-dns
  ports:
  - protocol: UDP
    port: 53
  - protocol: TCP
    port: 53

kubectl

kubectl apply -f netpol.yaml
kubectl get netpol
kubectl describe netpol allow-frontend

Exam gotchas

  • Empty podSelector: {} = all Pods in namespace
  • Policy matches Pod labels, not Service names
  • Egress deny breaks DNS: allow UDP and TCP 53 to kube-dns
  • NetworkPolicy requires CNI with policy support (Calico, Cilium, Weave); Flannel alone does NOT enforce

Practice scenario: Three-tier + NetworkPolicies

Tasks

  • NS production → 3 Deployments: tier=frontend|backend|database
  • Services: frontend LoadBalancer :80; backend ClusterIP :3000→80; database :5432
  • NetPol: backend ingress only from frontend on 3000
  • NetPol: database ingress only from backend on 5432
Solution
kubectl create ns production
kubectl create deploy frontend --image=nginx --labels=tier=frontend -n production
kubectl create deploy backend --image=nginx --labels=tier=backend -n production
kubectl create deploy database --image=postgres --labels=tier=database -n production
kubectl expose deploy frontend --port=80 --type=LoadBalancer --name=frontend-svc -n production
kubectl expose deploy backend --port=3000 --target-port=80 --name=backend-svc -n production
kubectl expose deploy database --port=5432 --name=database-svc -n production
# apply NetworkPolicy YAML: podSelector tier=backend/database + from podSelector + ports
kubectl get deploy,svc,netpol -n production

Concepts: NetPol podSelector = Pod labels; port-level ingress.