Getting started with AKS Network Policies

Siddiquimohammad
8 min readFeb 9, 2024

--

An important part of Container Security mechanism ‘Network Policy’ plays a very vital role in securing your cluster . It can help you to have a granular level of control on the traffic Ingressing or Egressing a Pod/Container. This reduces the attack surface by keeping unwanted traffic at bay .

Fig 1: Working of a Network Policy

Let’s highlight the things we will discuss before we begin

What is network policies in AKS ?

Why network policies ?

How to create a basic network policy ?

Ingress/Egress selectors

Combining selectors

Setting allowed port ranges

Kubernetes Default Network Policy examples

Best practices for Kubernetes Network Policies

What is network policy ?

Network Policies are a mechanism for controlling network traffic flow in Kubernetes clusters. They allow you to define which of your Pods are allowed to exchange network traffic. You should use them in your clusters to prevent apps from reaching each other over the network, which will help limit the damage if one of your apps is compromised.

Each Network Policy you create targets a group of Pods and sets the Ingress (incoming) and Egress (outgoing) network endpoints those Pods can communicate with.

There are three different ways to identify target endpoints:

  • Specific Pods (Pods matching a label are allowed)
  • Specific Namespaces (all Pods in the namespace are allowed)
  • IP address blocks (endpoints with an IP address in the block are allowed

Let’s consider the following example on an AKS cluster;

Fig 2 : Classic example of a Network Policy in Kubernetes

In the diagram above you can see we have a test-service which requires to accept TCP connections only from client-green pod and not from client-red. In such a situation a network policy can help you control this traffic flow as desired .

A network policy (a .yaml file) for the test-service would look something like this .

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-service-allowed-traffic
namespace: default
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: test-service
policyTypes:
- Ingress
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: client-green

We will discuss about the each and every line of the policy later. But as of now just keep in mind running this yaml on the cluster will create network routing rules which will block ingress traffic to test-service from client red whereas it will be allowed from client-green.

Okay !! we understood a basic example of what a Network policy can do on a cluster .. So now let’s get our concept cleared on WHY WE NEED A NETWORK POLCIY?

From the below pictorial representation of a Container attack surfaces , Insecure networking can be eliminated by configuring stringent Network policies

Fig 3 : Container attack surface

Let’s go through few attack scenarios in which a Network Policy can save the day

  1. Internet exposed Microservice hosted on AKS
Fig 4: Attack scenario 1
  • Microservice BE is exposed to Internet via External Nginx Ingress.
  • As per the design , traffic should flow from APIM -> Ingress -> Microservice BE
  • However, due to no network restrictions an attacker on Open Internet was able to establish TCP connection to the Microservice BE on open port 80/443.
  • If the Microservice BE is having any known vulnerability then it might lead to Initial access
Fig 5: Initial access
  • Adding a network policy for the nginx ingress Pod to accept traffic only from the APIM public IP will cut down the attack surface.

2. Compromised Microservice running on AKS

Fig 6: Attack scenario 2
  • An attacker has gained access to the App_X pod
  • This is a privileged Pod or the attacker has escalated the privilege by exploiting any existing loophole in the POD config.
  • Using this pod , attacker gets details about other pods/Host VM
  • Now the attacker can laterally move from one pod to another (as there is no restriction for pod-pod communication by default) & even to the Host VM ( if it has poor access restriction) thus increasing the attack surface.
Fig 7: Lateral movement
  • We can simply add a Network Policy for App_X pod to control the egress traffic . Practicing this for every pod will definitely help in reducing the attack surface

So it is evident that Network policies helps you to stop/frustrate the attacker at different stages of an attack.

Creating a basic network policy in AKS

Now we have an idea about What a network policy is & Why we need it at the first place . Let’s understand how to write these policies

Consider Fig 1

STEP 1 : Make sure CNI networking plugin is installed on your AKS cluster

STEP 2 : Determine the legit ingress and egress traffic for the pod

  • In our case it is client-green to test-service = Allow , client-red to test-service= Block
  • So we will create a policy for test-service pod to accept traffic accordingly

STEP 3 : Assign labels to your pods

  • To attach a Pod to a network policy, labels and selectors are used. First, a label is applied to the pod, for instance:
labels:
app.kubernetes.io/name: test-service


labels:
app.kubernetes.io/name: client-green

STEP 4 : Start writing the yaml — test.yaml

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-service-allowed-traffic --- name of the policy
namespace: default --- namespace in which network policy is to be applied
spec:
podSelector: --- type of selector
matchLabels:
app.kubernetes.io/name: test-service -- label of the pod for which the policy is created
policyTypes:
- Ingress -- Rules for ingress traffic
- from:
- podSelector: --- type of selector
matchLabels:
app.kubernetes.io/name: client-green --- Incoming traffc only being accepted from client-green . Rest all will be denied.

STEP 5 : Apply the yaml

 kubectl apply -f test.yaml

Hold on !!! We are not done here. This is just a basic .yaml example of a network policy. There are many more features a Network Policy offers

Ingress/Egress selectors

Your Network Policy Ingress and Egress rules can use a few different selector types to identify the Pods that are allowed to communicate with the policy’s target

  • podSelector — selects pod that match a defined set of labels
podSelector:
matchLabels:
app: test
  • namespaceSelector — is similar to podSelector but it selects an entire namespace using labels. All the Pods in the namespace will be included.
namespaceSelector:
matchLabels:
app: test

You can match a specific namespace by name by referencing the kubernetes.io/metadata.name label that Kubernetes automatically assigns:

namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: test-namespace
  • ipBlock — ipBlock selectors are used to allow traffic to or from specific IP address CIDR ranges. This is intended to be used to filter traffic from IP addresses that are outside the cluster. It’s not suitable for controlling Pod-to-Pod traffic because Pod IP addresses are ephemeral — they will change when a Pod is replaced.
ipBlock:
cidr: 10.0.0.0/24

Combining selectors

Combining selectors you can use multiple selectors to create complex conditions in your policies. The following policy selects all the Pods that are either labelled test-api or belong to a namespace labelled app: test

ingress:
- from:
- namespaceSelector:
matchLabels:
app: test
- podSelector:
matchLabels:
app: test-api

Above example represents a logical “or”. You can also create “and” conditions by combining selectors together as shown below:

ingress:
- from:
- namespaceSelector:
matchLabels:
app: test
podSelector:
matchLabels:
app: test-api

This policy only targets Pods that are both labelled app: test-api and in a namespace labelled app: test.

Setting allowed port ranges

The examples above permit allowed Pods to communicate using the entire available port range. However, adding a ports field to your Ingress and Egress rules lets you restrict this to just the ports your app actually requires:

ingress:
- from:
- podSelector:
matchLabels:
app: demo
ports:
- protocol: TCP
port: 32000
endPort: 32100

Now communication is only allowed on TCP ports in the range 32000 to 32100. You can omit the endPort field if you only use a single port.

Kubernetes Default Network Policy examples

  • Deny all traffic to a Pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: network-policy
spec:
podSelector:
matchLabels:
app: demo
policyTypes:
- Ingress
- Egress
  • Deny all traffic to all Pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: network-policy
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
  • Deny all ingress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: network-policy
spec:
podSelector: {}
policyTypes:
- Ingress
  • Deny all egress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: network-policy
spec:
podSelector: {}
policyTypes:
- Egress
  • Allow all traffic to a Pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: network-policy
spec:
podSelector:
matchLabels:
app: demo
policyTypes:
- Ingress
- Egress
ingress:
- {}
egress:
- {}

Best practices for Kubernetes Network Policies

Make sure to stick to the following 5 rules for a well-structured and effective Network policies

1. Ensure all Pods are covered by a Network Policy

All Pods in a Kubernetes cluster should be subject to Network Policies that limit their network interactions to the minimal set of Ingress/Egress targets they require. Not setting Network Policies allows all Pods to communicate, which is a potential security risk.

2. Use precise Ingress/Egress target selectors

Keep your Pod selectors, namespace selectors, and ipBlock ranges as precise as possible to prevent them from accidentally selecting new Pods in the future. For example, a namespace selector is inappropriate if you’re likely to deploy additional Pods to the namespace, and those Pods shouldn’t automatically communicate with your Network Policy’s target.

3. Set a default deny policy, then add your allow policies

You can ensure your cluster has complete Network Policy coverage by creating a default “deny all” policy (as shown in the example above), then adding specific “allow” policies that authorize required traffic flows. This method means new Pods are protected from accidental network exposure, even if you forget to create a specific Network Policy for them.

4. Regularly review your policies and keep them updated

Your Network Policy requirements are likely to change as your cluster evolves with new Pods and namespaces. You should regularly review your policies and make any alterations required so they remain appropriate for your environment.

5. Test your policies to check they’re working as intended

One of the difficulties associated with Network Policies is the lack of clear visibility into whether they’re working. It’s worthwhile to test new policies to be sure they’re configured correctly. As in the examples above, you can create a new Pod with labels that match your Network Policy’s selectors, then use commands like curl and ping to test the connectivity available within the container.

Okay so this sums up our discussion. In next article we will implement end-to-end Network Policy for a microservice application hosted on AKS.

--

--