Kubernetes Network Policy

In this post I will show you how you can use NetworkPolicys in K8S.

Parst of the K8S Security series

Network policies

Network policies are Kubernetes resources that allows to control the traffic between pods and/or network endpoints. Most CNI plugins support the implementation of network policies, but if they don’t the created NetworkPolicy will be ignored.

The most popular CNI plugins with network policy support are:

  • Weave
  • Calico
  • Canal
  • Cilium

Example

A good practice is to define and apply a default NetworkPolicy to deny all incoming traffic to all pods in all application namespaces, then whitelist pods and subnets based on application needs.

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

Since this resource defines both policyTypes ingress and egress, but doesn’t define any whitelist rules, it blocks all the pods in the monitoring namespace from communicating with each other. All NetworkPolicy is like a firewall rule. To select an aplication you need to use selectors of labels. To allow connections from the Ingress Controller:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-ingress
spec:
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          app.kubernetes.io/name: ingress-nginx
  podSelector: {}
  policyTypes:
  - Ingress

We need to create allow rules to define what aplication can communicate with anathor aplication. To match network traffic by combining namespace and pod selectors, you can use a NetworkPolicy object similar to the following:

apiVersion: extensions/v1beta1
kind: NetworkPolicy
metadata:
  name: alertmanager-mesh
  namespace: monitoring
spec:
  podSelector:
    matchLabels:
      app: alertmanager
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: prometheus
    - namespaceSelector:
        matchLabels:
          name: monitoring
    ports:
    - port: 9093
      protocol: tcp
  policyTypes:
  - Ingress

Allow inbound tcp to port 9093 from only prometheus to node-exporter

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: prometheus
  namespace: monitoring
spec:
  podSelector:
    matchLabels:
      app: prometheus
  ingress:
  - from:
    - podSelector: {}
    - namespaceSelector:
        matchLabels:
          name: monitoring
    ports:
    - protocol: TCP
      port: 9090
  policyTypes:
  - Ingress

Allow inbound tcp to port 9090 from any source to prometheus.

You can create Rules to allow outboudn trafic from a service to a apps with specific tags. The following policy allows pod outbound traffic to other pods in the same namespace that match the pod selector. In the following example, outbound traffic is allowed only if they go to a pod with label color=red, on port 80.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-egress-same-namespace
  namespace: default
spec:
  podSelector:
    matchLabels:
      color: blue
  egress:
  - to:
    - podSelector:
        matchLabels:
          color: red
    ports:
    - port: 80

If You Don’t Know Which Pods Need To Talk To Each Other you can allow all application in a namespace to connect with each other.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}

Another good practice is to define and apply a default NetworkPolicy to deny egress traffic outside of the cluster for application namespaces, then whitelist any external subnets for pods as needed.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-external-egress
  namespace: prod
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector: {}

For services that require egress to resources outside of the cluster, for example, a database whitelist the subnet that the network resource is on.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: customer-api-allow-web
  namespace: prod
spec:
  podSelector:
    matchLabels:
      app: orders
  policyTypes:
  - Egress
  egress:
  - ports:
    - port: 3306
    to:
    - ipBlock:
        cidr: 172.16.32.0/27

It is important to enforce separation of containers. As you can see you can create a NetworkPolicy for a specific namespace. So don’t forget to create the default best practice Policies. In the next post will show you how you can automate the creation of the Default Policies for new namespaces.