Kubernetes

How to protect Kubernetes cluster traffic with pod network policies

Written by MilanMaximo

Kubernetes Pods are free to communicate with each other by default. This poses a security risk when your cluster is used for multiple applications or teams.
Misbehavior or malicious access in one Pod can direct traffic to other Pods in your cluster. 

In this article, I will try to explain to you how to avoid this scenario and how to protect Kubernetes cluster traffic by configuring network policies.
These rules allow you to control the flow of traffic between Pods at the level of IP addresses (OSI layer 3 or 4).
You can fine-tune the sources of incoming and outgoing traffic allowed for each Pod.

Create a network policy

Network policies are created by adding NetworkPolicy objects to the cluster.

Each policy defines the Pods it applies to and one or more ingress and egress rules.

Here is the basic policy manifest:

policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy
  namespace: app
spec:
  podSelector:
    matchLabels:
      component: database
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
      - podSelector:
          matchLabels:
            component: api
  egress:
    - to:
      - podSelector:
          matchLabels:
            component: api

This network policy applies to any Pod labeled component: database in the app namespace.
It states that incoming (ingress) and outgoing (egress) traffic is only allowed from and to a Pod labeled component: API.

Any requests from other Pods, such as component: web-frontend, will be blocked.
Network policies can be applied like any other object using Kubectl.

They will take effect immediately after creation.
You can add a network policy before the Pods it selects start.

How Network Policies work

$ kubectl apply -f policy.yaml
networkingpolicy.networking.k8s.io/network-policy created

Network policies are implemented by your cluster’s active network plugin.
Your policies will have no effect if your plugin does not support this feature.

Most of the popular options like Calico and Cilium come with network policy support enabled.

When a network policy is applied to a Pod, the plugin checks its traffic against the policy requirements.
Any connections that do not meet the criteria will be denied.

The Pod that tried to initiate the connection will find that the remote host is unreachable, either because it was trying to access a resource blocked by the egress rule, or because the remote Pod denied the incoming connection with the ingress rule.

A successful connection between two Pods can only be established when the network policies of both Pods allow it.
The connection can be denied by the initiating Pod’s egress rule or the target Pod’s ingress rule.

Network policies are always additive in nature. When multiple policies select the same Pod, the list of allowed entry and exit sources will be a combination of all policies.

Network Policy Examples

Network policies support many different options for configuring target subsystems and the types of connections allowed.
The following examples demonstrate several common use cases.

Apply the policy to each Pod in the namespace, allowing incoming traffic only from a specific block of IP addresses.

YAML
apiVersion : networking.k8s.io/v1
kind : NetworkPolicy
 metadata :
  name : network-policy
  namespace : app
 spec :
  podSelector : { }
  policyTypes :
    - Ingress
  ingress :
    - from :
       - ipBlock :
         cidr : 172.17.0.0/16
YAML

An empty podSelector block means that the policy targets all Pods in the namespace.

The ipBlock rule restricts incoming traffic to Pods with an IP address in the specified range.
Outgoing traffic is not blocked.

Allow incoming traffic from a block of IPs, but exclude some specific IPs.

YAML
apiVersion : networking.k8s.io/v1
 kind : NetworkPolicy
 metadata :
   name : network-policy
   namespace : app
 spec :
  podSelector : { }
  policyTypes :
      - Ingress
  ingress :
    - from :
      - ipBlock :
          cidr : 172.17.0.0/16
          except :
             - 172.17.0.1/24
             - 172.17.0.2/24
             - 172.17.0.3/24

ipBlock rules support an except field to exclude traffic originating from or directed to specific IP addresses.

Allow incoming traffic from all subsystems in the namespace, but only from a specific port.

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy
  namespace: app
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector: {}
          ports:
            - protocol: TCP
              port: 443

 

The ports field is available for entry and exit rules.

You can optionally specify a range of ports, such as 3000 – 3500, by specifying the endPort (3500) field in addition to port (3000).

Allow traffic from Pods with a specific tag that exists in a different namespace.

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy
  namespace: database
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              application: demo-app
          podSelector:
            matchLabels:
              component: database

 

The policy states that any Pod tagged with component: database can reach all Pods in the database namespace as long as its own namespace is tagged demo-app.

You can allow traffic from all Pods in an external namespace by creating a rule that includes only the namespaceSelector field.

Explicitly allow all traffic

Sometimes you may want to explicitly allow all traffic of a certain type in a namespace.

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy
  namespace: app
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - {}
  egress:
    - {}


All Pods in the namespace are free to communicate as if there were no policy.
Creating a policy in any case allows you to communicate your intentions to other users of the cluster.

They may question the existence of an unrestricted networking namespace in an otherwise secure cluster.

When to Use Network Policies

In Kubernetes, network policies are used to isolate Pods and control the flow of traffic between them. It is important to create a network policy for each namespace and Pod in your cluster in order to better protect your containers and minimize the risk of a hack.

It is recommended to make your policies as specific as possible, rather than allowing broad access between all Pods in a namespace. Keep in mind that Kubernetes does not include network policies by default, so you need to set them up manually in order to properly protect your Pods.

You can mitigate this risk by adding a generic policy to the namespace.

This policy selects every Pod in the namespace and enforces a rule that prevents all network communication:

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: app
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Bonus:

If you work with Azure Cloud you can check this document how to protect Kubernetes cluster and secure traffic between pods using network policies

Conclusion

Kubernetes allows all Pods in your cluster to communicate with each other.

Network policies could really protect Kubernetes cluster.

For real applications running in multipurpose clusters, this is too much leeway.

Network Policies solve this problem by providing a firewall-like system to control the incoming sources and outgoing targets that each Pod accepts.

About the author

MilanMaximo

Leave a Comment