Simplifying kubernetes network policies with cilium

Blog banner image


Kubernetes network policies can be difficult to write but the free cilium editor makes it really simple



By default, pods can communicate with anything both in the kubernetes cluster and outside (unless blocked by a firewall). This is a poor practice and you should restrict this communication to only allow certain pods to talk to other specific pods or external services. By doing this we significantly reduce the services accessible to a compromised pod and ensure pods only communicate with services we expect. This is where network policies come in.

Network policies are kubernetes resources, just like pods and deployments. Typically you will interact with them in their yaml format. With network policies deployed, it is trivial to quickly audit the permitted network traffic for an application and understand how it interacts with other services.

To understand how network policies work in Kubernetes, it’s helpful to first understand the way that pods communicate with each other within a cluster.

To create a network policy, you first need to specify the pods that you want to include in the policy. This is done using labels, which are key-value pairs that are attached to pods. You can then create a network policy that specifies which labels should be allowed to communicate with which other labels.

For example, you might have a group of pods that handle sensitive data, and you only want these pods to communicate with a smaller group of pods that handle authentication. In this case, you could create a network policy that allows only the authentication pods to communicate with the sensitive data pods.

Here is an example:

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: permit-sensitive-pod-egress
spec:
  podSelector:
    matchLabels:
      app: sensitive
  policyTypes:
    - Egress
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: auth
      ports:
        - port: 80
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: permit-auth-ingress
spec:
  podSelector:
    matchLabels:
      app: auth
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: sensitive
      ports:
        - port: 80

So how do they work?

Once you have created your network policy, it is enforced by the network plugin in use. There are several different network plugins available for Kubernetes, and each one has its own way of implementing network policies. Some plugins, such as Calico, use iptables rules to enforce policies, while others use different methods.

Network policies work for services too, you just use the relevant pod labels as normal and use the port definitions for the pod, not the service.

It’s important to note that network policies are enforced at the pod level, not at the container level. This means that if a pod has multiple containers, all of those containers will be subject to the same network policy. This is because containers share the same network space within a pod and are scheduled on the same node. Containers can talk to each other on localhost and cannot bind the same ports!

So what is the cilium visual editor?

Network policies can get pretty complicated and they are quite difficult to write even when they are simple. The earlier example of just one flow required two definitions, one for ingress and another for egress. We also haven’t added a policy to permit DNS resolution, so no pods in the namespace can resolve and DNS.

To make the process much simpler, and prevent accidentally isolating our pods, we can use the cilium visual editor which is a free service from cilium. With this tool you can enter your network flows into the app and have it generate the definition for you.

We always find it useful to add a base policy to each namespace with no permitted traffic flows. Kubernetes allows all traffic by default, so adding this policy flips that. With this in place, no traffic is permitted unless another policy allows it. It looks like this:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: block-all
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress: []
  egress: []

From here, you write your definitions. We try to keep them simple and readable, like the first example where we have a single policy per flow. This makes understanding flows much easier, and maintaining them simple.

You can get more info on the cilium editor over on their release article

For more information, email us at [email protected] or call us on 0161 660 3545

Author

Simon Gurney

- CTO -

Simon is one of the Punk Security Directors and has over 17 years experience working within IT, primarily focused on automation and InfoSec.

read more