Skip to main content

Network Access Policies

Kubernetes Network Policies controls traffic flow inside and across namespaces in the cluster. It allows you to explicitly control who are allowed to communicate with your service, and who your service is allowed to communicate with. The default policy in Gjensidige's clusters is to deny all incoming and outgoing traffic, creating a Zero Trust Networking Model where services are not trusted by default.

Default Network Policy

The following NetworkPolicy is applied to all team namespaces:

namespace-default.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: "namespace-default"
namespace: "<team-namespace>"
spec:
podSelector: {} # Match all pods in namespace
policyTypes:
- Egress
- Ingress
egress:
- to:
- ipBlock:
cidr: "0.0.0.0/0" # Allow egress out of the cluster
except: # Deny egress to pods inside the Kubernetes private network
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: "kube-dns" # Allow egress to kube-dns to be able to resolve dns names
ingress:
- from:
- namespaceSelector: # Allow ingress from NGINX
matchLabels:
name: "system-ingress"
podSelector:
matchLabels:
app-name: "ingress-nginx"

# Some ingress policies including common monitoring tools like Prometheus are left out for brevity

Overriding the default policy

If your service needs to communicate with other services inside the cluster, you can add policies specific to selected pods on top of the default policy. Consider the following diagram:

Network policies example

In this example, "pod-1" wants to talk to "pod-2", and "pod-2" wants to talk to "pod-3". To allow this, we have to define a NetworkPolicy for each of the pods.

Let's start with "pod-1". This pod wishes to send traffic to "pod-2", but don't want to receive traffic from any other pod. Hence, we only need to specify a rule for egress traffic:

pod-1-networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: "pod-1-netpol"
namespace: "team-one-namespace"
labels:
app: "pod-1"
spec:
podSelector:
matchLabels:
app: "pod-1"
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: "pod-2"

Next is "pod-2" which wished to send traffic to "pod-3" and receive traffic from "pod-1". In this case we need to specify rules for both egress and traffic:

pod-2-networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: "pod-2-netpol"
namespace: "team-one-namespace"
labels:
app: "pod-2"
spec:
podSelector:
matchLabels:
app: "pod-2"
policyTypes:
- Egress
- Ingress
egress:
- to:
- namespaceSelector: # Required to specify 'namespaceSelector' if pod is in another namespace
matchLabels:
name: "team-two-namespace"
podSelector:
matchLabels:
app: "pod-3"
ingress:
- from:
- podSelector:
matchLabels:
app: "pod-1"

Last is "pod-3" which wants to receive traffic from "pod-2" and don't send traffic to anyone. We only need a rule for ingress traffic in this case:

pod-3-networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: "pod-3-netpol"
namespace: "team-two-namespace"
labels:
app: "pod-3"
spec:
podSelector:
matchLabels:
app: "pod-3"
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector: # Required to specify 'namespaceSelector' if pod is in another namespace
matchLabels:
name: "team-one-namespace"
podSelector:
matchLabels:
app: "pod-2"

Having defined these NetworkPolicies for each pod, they should be able to communicate as shown in the diagram 🎉

Using Network Policies with Kustomize

Specifying podSelector.matchLabels when using Kustomize and commonLabels might have unexpected consequences as all occurrences of matchLabels will get the specified common labels appended. Using podSelector.matchExpressions might be a better solution in this case. Refer to this GitHub issue for more details.