Skip to content
Rahul Shishodiaon GitHub LinkedIn profile

Network Policies

  • Declarative only: no kubectl create networkpolicy
  • Requires network policy controller (CNI plugin): assume installed on exam
  • Default: all traffic allowed until a policy selects Pods

Spec structure

  • podSelector: which Pods policy applies to
  • policyTypes: [Ingress], [Egress], or both
  • ingress / egress rules: from/to, ports

Allow specific traffic

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes: [Ingress]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080

Interpretation: policy applies to tier=backend; only tier=frontend Pods may connect to those Pods on TCP 8080. Everything else to selected Pods is denied for that policy type.

Default deny-all

spec:
  podSelector: {}      # all Pods in namespace
  policyTypes: [Ingress, Egress]
  # no ingress/egress rules = deny all

Cross-namespace

ingress:
- from:
  - namespaceSelector:
      matchLabels:
        kubernetes.io/metadata.name: other-ns
    podSelector:
      matchLabels:
        app: client

ipBlock (external / CIDR-based traffic)

Use ipBlock to allow traffic to/from IP ranges (e.g. external load balancers, on-prem systems):

# Allow ingress from a specific external CIDR
ingress:
- from:
  - ipBlock:
      cidr: 192.168.1.0/24
      except:
      - 192.168.1.5/32   # exclude a specific IP

# Allow egress to an external API (e.g. 203.0.113.0/24)
egress:
- to:
  - ipBlock:
      cidr: 203.0.113.0/24
  ports:
  - protocol: TCP
    port: 443
  • ipBlock matches by IP address, not labels
  • except field excludes sub-ranges from the allowed CIDR

Allow DNS (required when using default-deny egress)

If you apply a default-deny egress policy, all DNS lookups break. Always allow DNS:

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

Selector logic

  • Multiple entries in from → OR
  • Multiple conditions in one selector entry → AND
# OR: frontend OR cache can connect
from:
- podSelector:
    matchLabels:
      tier: frontend
- podSelector:
    matchLabels:
      tier: cache

# AND: pods with tier=frontend inside namespaces labeled name=prod
from:
- namespaceSelector:
    matchLabels:
      name: prod
  podSelector:
    matchLabels:
      tier: frontend

Debug blocked traffic

kubectl get netpol -n <ns>
kubectl get netpol <name> -n <ns> -o yaml
kubectl get po -n <ns> --show-labels
kubectl exec <source> -n <ns> -- wget -qO- --timeout=2 http://<svc>:<port>

Common shapes

# Deny all ingress to all Pods in a namespace
spec:
  podSelector: {}
  policyTypes: [Ingress]
  ingress: []

# Allow egress to database and DNS only
policyTypes: [Egress]
egress:
- to:
  - podSelector:
      matchLabels:
        tier: database
  ports:
  - protocol: TCP
    port: 5432
- to: []
  ports:
  - protocol: UDP
    port: 53

kubectl

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

Exam tips

  • Empty podSelector: {} = all Pods in namespace
  • Policy must match Pod labels, not Service names
  • Egress deny breaks DNS: allow UDP and TCP 53 to kube-dns in kube-system
  • ipBlock and podSelector can be combined in the same from[] list (OR logic)
  • "Allow X to Y" usually means an ingress policy on Y
  • NetworkPolicies do nothing unless the cluster CNI enforces them