Octet

How do Kubernetes NetworkPolicies work, and what usually goes wrong with them?

Show the answer

Say this first

By default every pod can talk to every pod. Once any NetworkPolicy selects a pod for ingress or egress, that direction becomes deny by default for the pod and only what some policy allows gets through. Policies are additive allow lists with no deny rule. They only work if the CNI enforces them, and the classic mistakes are forgetting DNS on egress and mixing up the AND versus OR form of selectors.

Go deeper

Default deny plus an allow

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: shop
spec:
  podSelector: {}
  policyTypes: [Ingress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-from-web
  namespace: shop
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web
      ports:
        - protocol: TCP
          port: 8080

The AND vs OR trap

YAML
# One element: namespace AND pod must match
- from:
    - namespaceSelector: {matchLabels: {team: web}}
      podSelector: {matchLabels: {app: web}}
# Two elements: namespace OR pod matches
- from:
    - namespaceSelector: {matchLabels: {team: web}}
    - podSelector: {matchLabels: {app: web}}

One dash changes the meaning and can open a namespace wide.

Enforcement

Calico, Cilium, the AWS VPC CNI with its network policy agent, and Azure's options enforce policies. Flannel alone does not, and the API server accepts the objects anyway, so nothing warns you.

Traps

  • Assuming policies work on any cluster. The CNI must enforce them.
  • Forgetting that a policy with only ingress rules leaves egress wide open for the same pods.
How did you do?