Earlier this week my girlfriend (who is a networking ninja) asked a great question, how do you secure traffic between pods in Azure Kubenetes Service (AKS).
This simple sounding question started a two-day hack to allow us to experiment with deploying AKS and configuring network policies. As it turns out, this functionality is currently in preview, so it wasn’t as simple as it might have first appeared.
In this post, I’m going to outline the basics of a demo that demonstrates the process. If you’re interested in following this tutorial then you’ll be pleased to hear you don’t have to install any tools locally!
Cloud Shell
The Cloud Shell is a browser-based shell experience available anywhere, providing you can log into the Azure portal. With the Cloud Shell, you are able to pick between either Bash or Powershell, which is great for me as a long time macOS user now sporting a Dell.
Cloud Shell Scripts
When I first saw the Cloud Shell, I assumed it was only good for executing individual commands but its just as powerful as PowerShell on my Dell or Bash on my Mac. This is because it’s backed by Azure File Storage, which allows us to upload and execute existing shell scripts.
Using the Cloud Shell with scripts makes it super easy to quickly deploy services in a reproducible way, without having to install and configure any tools on your local development machine, which is a HUGE win!
Preview Features
This feature is in preview, so before we start, we need to enable it. In the Cloud Shell, enter the following:
az feature register --name EnableNetworkPolicy --namespace Microsoft.ContainerService
This can take a few minutes but only ever needs to be done just the once! Once It’s completed, you can query its status using the following:
az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/EnableNetworkPolicy')].{Name:name,State:properties.state}
Once registered is success, you’ll need to run the following to finish up:
az provider register -n Microsoft.ContainerService
Creating an AKS Instance
Now for the interesting bits! We’re going to deploy a new AKS cluster! Because we’ll be using the same names throughout the process, we’ll go ahead and define these as variables.
export RESOURCE_GROUP_NAME=my-aks-demo
export CLUSTER_NAME=my-AKS1
Create a resource group
az group create --name $RESOURCE_GROUP_NAME --location eastus
Create a Virtual Network & Subnet
az network vnet create --resource-group $RESOURCE_GROUP_NAME --name myVnet --address-prefixes 10.0.0.0/8 --subnet-name myAKSSubnet --subnet-prefix 10.240.0.0/16
We get the Virtual Network Subnet Resource ID
SUBNET_ID=$(az network vnet subnet show --resource-group $RESOURCE_GROUP_NAME --vnet-name myVnet --name myAKSSubnet --query id -o tsv)
az aks create --resource-group $RESOURCE_GROUP_NAME --name $CLUSTER_NAME --kubernetes-version 1.12.4 --network-plugin azure --service-cidr 10.0.0.0/16 --dns-service-ip 10.0.0.10 --docker-bridge-address 172.17.0.1/16 --vnet-subnet-id $SUBNET_ID --network-policy calico --generate-ssh-keys
Nows the time to pop your feet up and relax as this is going to take a while. On average it takes about 10 minutes to finish. Once it has though, it’ll have spun up a new AKS cluser which means we can grab a copy of the Kubernetes Context using Kubectl:
az aks get-credentials --resource-group $RESOURCE_GROUP_NAME --name $CLUSTER_NAME
Deploying something!
We need to deploy something to AKS in order to confirm that the network policies are working. We don’t need anything too complex so a NGINX Container it is! We’ll give it a label of “app=api” and expose the pod.
kubectl run api --image=nginx --labels app=api --expose --port 80
By default, any other containers should be able to communicate with the API we just deployed, so lets confirm! To do that,we’ll go ahead and deploy another container.
kubectl run --rm -it --image=alpine test-np
Testing, Testing, 123
Lets test if it works! To do this, we can use the prompt and enter the following:
wget http://api -qO-
We should then get some HTML passed back as text.
Deny Policy
So we know we can communicate, which is default behavior, lets deploy a network policy which will deny the communication. The policies are super simple, in fact the sample here is only 9 LOC!
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: api-policy
spec:
podSelector:
matchLabels:
app: api
ingress: []
With this saved to disk (or uploaded to the Cloud Shell), we can call the following:
kubectl create -f [RootDirectory]/deny.yaml
Testing
To retest we’re going to need to reattach to the pod. To do this, enter the following:
kubectl attach [test-np name] -i -t
We can then repeat the process above but adding a timeout to ensure we don’t wait until boredom or death occurs before being told it failed. (its default is 30 seconds…)
wget -qO- --timeout=2 http://api
Wrap Up
You’re now a cutting edge, AKS networking ninja!
Well, perhaps not exactly but you’ve at least learn the basic of this new feature to AKS. To learn more about this new feature then check out the offical documentation on the Microsoft site.
Huge thanks and credit goes to Simona Tarantola & Justin Davies. This post wouldn’t have been possible without them!
One Comment