Network Policy in K8s

Introduction

Inside Kubernetes, by default, every pod or service can talk to each other. This creates a security problem if the frontend gets connected to the database.

So, we need to apply some kind of rule so that we can control which resource can connect to which one. This traffic can be egress (outgoing from the pod) or ingress (incoming to the pod).

These things will be defined in the network policy file, and we will apply that in the cluster.

Here is a sample network policy file, which will restrict the frontend from connecting with the DB, and only the backend can do that.

This one is with incoming or Ingress

where the backend pod is labeled as role=backend, and it will connect only on port 3306.


apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-backend
spec:
  podSelector:
    matchLabels:
      name: mysql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: backend
    ports:
    - port: 3306

This one with Egress

Here, for example, DB can only connect to the backend, but incoming traffic is allowed for all.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-backend
spec:
  podSelector:
    matchLabels:
      name: mysql
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          role: backend

Complete setup

This is the complete file with ingress and egress applied.


apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-backend
spec:
  podSelector:
    matchLabels:
      name: mysql
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: backend
    ports:
    - protocol: TCP
      port: 3306
  egress:
  - to:
    - podSelector:
        matchLabels:
          role: backend

Now if you want to use IP instead of pod and service labels, here is an example for that.


apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-backend
spec:
  podSelector:
    matchLabels:
      name: mysql
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 10.10.20.15/32
    ports:
    - protocol: TCP
      port: 3306
  egress:
  - to:
    - ipBlock:
        cidr: 10.10.20.15/32

Now if you want to restrict a whole namespace. Here only the namespace payments can connect to DB.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-payments-to-mysql
  namespace: default
spec:
  podSelector:
    matchLabels:
      name: mysql

  policyTypes:
  - Ingress

  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          team: payments
    ports:
    - protocol: TCP
      port: 3306

Remember while applying any egress rule, By default, pods can access everything, including the DNS server in your cluster.

When you define an egress NetworkPolicy, Kubernetes applies default deny for egress to the pods it selects. This means all outgoing traffic is blocked, including traffic to the DNS server. So after applying a restrictive egress policy, pods can no longer resolve domain names.

So you need to apply this complete file which will not block the DNS.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-backend-with-dns
  namespace: default
spec:
  podSelector:
    matchLabels:
      name: mysql
  policyTypes:
  - Ingress
  - Egress

  # Ingress: only backend pods can connect
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: backend
    ports:
    - protocol: TCP
      port: 3306

  # Egress: only backend pods + DNS
  egress:
  # Allow egress to backend pods
  - to:
    - podSelector:
        matchLabels:
          role: backend

  # Allow DNS traffic to kube-dns in kube-system
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

One more thing is there, not all CNIs supports this network policy. The kind-net CNI which comes by default with the kind and minikube cluster and Flannel does not support this. These some of the open-source CNI which supports Network Policy.

  1. Calico
  2. Cillium
  3. Kube-router
  4. Weave-Net
  5. Romana