Featured image of post Testing Calico on AKS - Ingress Traffic

Testing Calico on AKS - Ingress Traffic

In this post, we will continue to explore Calico network policies in Azure Kubernetes Service. We will configure a simple policy to allow ingress traffic from a central ingress controller.

Prerequisites

As always, we will need a few prerequisites.

  • An Azure account and valid subscription.
  • An AKS cluster configured with
    • Azure AD integration for cluster access
    • Azure CNI network plugin
    • Calico
  • A workstation with the following tools installed
    • az cli
    • kubectl
    • calicoctl
    • helm version 3

Deploy nginx ingress controller

By default, no ingress controller is deployed inside your AKS cluster. We will thus deploy the one from nginx using the official helm chart as described in AKS official documentation page.

# Create a namespace for your ingress resources
kubectl create namespace ingress-basic

# Add a label to ingress-basic namespace that will act as selector for Calico policy
kubectl label namespace ingress-basic env=ingress-basic

# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# Use Helm to deploy an NGINX ingress controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
    --namespace ingress-basic \
    --set controller.replicaCount=1 \
    --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
    --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \
    --set controller.admissionWebhooks.patch.nodeSelector."beta\.kubernetes\.io/os"=linux

# Check the helm release
helm list -n ingress-basic
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
nginx-ingress   ingress-basic   1               2021-01-19 09:32:58.7207368 +0100 CET   deployed        ingress-nginx-3.20.1    0.43.0     

Caution : deploying an ingress controller with the helm chart does provision an additional external ip address on your cluster’s Azure Load Balancer which incurs additional costs.

Check the status of the ingress service that is exposed externally through an Azure load balancer.

kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller
NAME                                     TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGE     SELECTOR
nginx-ingress-ingress-nginx-controller   LoadBalancer   192.168.62.68   <external ip>   80:32537/TCP,443:31205/TCP   4m21s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx

Deploy the hello-world sample application

We will use a sample hello-world application that we will deploy in the development namespace already configured with basic Calico policies. See my article on Testing Calico on AKS with Azure CNI for further info on how to setup this namespace and the Calico policies.

Create a deployment file with the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aks-helloworld
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aks-helloworld
  template:
    metadata:
      labels:
        app: aks-helloworld
    spec:
      containers:
      - name: aks-helloworld
        image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
        ports:
        - containerPort: 80
        env:
        - name: TITLE
          value: "Welcome to Azure Kubernetes Service (AKS)"
---
apiVersion: v1
kind: Service
metadata:
  name: aks-helloworld  
spec:
  type: ClusterIP
  ports:
  - port: 80
  selector:
    app: aks-helloworld

Apply this deployment to the development namespace.

# Deploy the application and the internal service
kubectl apply -f aks-helloword-deployment.yaml -n development

Configure the ingress route

Create a file aks-helloworld-ingress.yaml with the following content :

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
  namespace: development
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: aks-helloworld
          servicePort: 80
        path: /hello-world(/|$)(.*)
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress-static
  namespace: development
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /static/$2
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: aks-helloworld
          servicePort: 80
        path: /static(/|$)(.*)

Apply the ingress route definition in the development namespace where the aks-helloworld resources have been deployed

kubectl apply -f hello-world-ingress.yaml -n development

Remark : nginx-ingress controller deployed with helm chart watches ingress rules in all namespaces.

Open a web browser and test the access to the application by calling the URL http://<ingress-external-ip>/hellow-world.

fig1 - error 504

You will receive a 504 timeout and this is expected because we did not yet define a network policy to allow ingress traffic coming from ingress-basic namespace to our pods running in development namespace.

Create a Calico network policy to allow the ingress traffic.

# Apply the network policy to accept ingress
calicoctl apply -f 06-allow-ingress-from-nginx.yaml

# Check the applied network policies in the development namespace
calicoctl get networkpolicies -n development
NAMESPACE     NAME                   
development   default-deny           
development   development-ns-allow   
development   dns-allow              
development   nginx-ingress-allow    
development   sqlserver-allow  

Now run the test once again …

fig2 - success

Ta daaaaa! Now it works as expected.

Conclusion

Calico makes it really easy to define network policies to control the traffic coming from ingress controller to your pods. It requires some discipline and makes your Kubernetes cluster a safer place :)

Try to not overengineer your network policies otherwise it can become difficult to manage. As always, a good balance between security and ease of management must be found and it all depends on your requirements.

Built with Hugo
Theme Stack designed by Jimmy