A first look at Network Policies in Tanzu Mission Control

Some time back, I wrote a blog post about how to use the network policies available with the Antrea CNI (Container Network Interface). In that post we looked at how to create a simple network policy to prevent communication between pods in a Tanzu Kubernetes cluster, based on pod selectors / labels. We stood up a simply web server and a standalone pod, and showed how the pod could access the web server when no network policies were in place. We then proceeded to create a network policy that only allowed pods to communicate to each other if the pod selector / label matched the rule defined in the policy. In this post, I am going to look at how to do the same operation in Tanzu Mission Control. Again, the Kubernetes cluster will be TKG v1.3.1 (K8s 1.20.5). I will create a namespace, then create a Nginx deployment + service along with a standalone busybox pod. To begin, the busybox will have a different label to Nginx. We will show how, without a network policy, the busybox pod can communicate with the Nginx service. We will then implement a network policy that only allows pods with a certain label to communicate, so in this case, the busybox pod will no longer be able to communicate with the web server. Finally, we will change the pod selector / label rule in the network policy to match that of the busybox pod and we should see successful communication once again.

Step 1 – Create namespace and apps

I created a namespace called network-testing on my TKG cluster. I deployed the Nginx application, and my standalone busybox pod. Note how they have different labels as shown by the APP column. Also note the Cluster-IP address for the Nginx service, highlighted in blue below. We will be using this to test communication between the pods.

$ kubectl get all -n network-testing -L app
NAME                              READY  STATUS    RESTARTS  AGE    APP
busybox                           1/1    Running  0          9m1s  busybox
nginx-deployment-585449566-8p27j  1/1    Running  0          9m9s  nginx
nginx-deployment-585449566-nsd7k  1/1    Running  0          9m9s  nginx
nginx-deployment-585449566-rqfp5  1/1    Running  0          9m9s  nginx

NAME                TYPE          CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE  APP
service/nginx-svc  LoadBalancer  100.67.183.176  10.35.14.224  443:31991/TCP,80:30903/TCP  21m  nginx

NAME                              READY  UP-TO-DATE  AVAILABLE  AGE  APP
deployment.apps/nginx-deployment  3/3    3            3          21m

NAME                                        DESIRED  CURRENT  READY  AGE  APP
replicaset.apps/nginx-deployment-585449566  3        3        3      21m  nginx

Step 2 – Verify pod communication without network policy

To make sure we have pod to pod communication in place without any network policy created, we can use the following test. After opening a shell to the busybox pod, we should be able to run a wget against the Cluster-IP of the Nginx service and retrieve the web server landing page, as shown below. This demonstrates that there is communication between the different pods.

$ kubectl exec -it busybox -n network-testing -- sh
/ # wget -q -O - 100.67.183.176
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
/ #

We can now try to control this communication with a network policy.

Step 3 – Create a Workspace in Tanzu Mission Control

In order to be able to create a network policy in Tanzu Mission Control (TMC), it must be created at the workspace level. A workspace is an organizational tool that helps you monitor and manage your Kubernetes namespaces within and across clusters. Creating the workspace is very simple. From the main TMC landing page, there is a Workspace link on the left-hand navigation bar. Click on this, and then click on the button to Create Workspace. Give it a name, and optional description and optional labels, and that is it. For this example, I created a workspace called network-testing-ws.

Step 4 – Attach the namespace to the Workspace in TMC

Once the workspace is created, add your namespace to it. As previously mentioned, I created a namespace called network-testing for this post. To add this namespace to the workspace, select Namespaces from the navigation bar on the left-hand side, select the namespace that you want to attach, and then click the Attach button. With the namespace now attached to the workspace, we can proceed with the creation of the network policy. In this screenshot, I have attached my network-testing namespace to the network-testing-ws workspace.

Step 5 – Navigate to ‘create a network policy’

Network policies can only be created at the workspace level. They cannot be created at cluster level or at a namespace level. Thus, to get to the point where you can create a network policy, you must first expand the Policies section in the left-hand navigation bar. This will show a sub-menu item called Assignments. Click on this and it will take you to the Policies section. Across the top, there will be a number of menu items. Select Network. Now you have the option of selecting Cluster or Workspace. If Cluster is selected, it will tell you that you cannot set network policies at the cluster level, only at the workspace level. Select Workspace, and then select the workspace you want to create a policy on. In our case, the workspace is network-testing-ws. Now you should see the option to create a network policy on the right hand side of the window.

Step 6 – Create a Network Policy

Click on the Create Network Policy link shown above. For the purposes of this demonstration, I am going to create a custom-ingress policy. I will give the policy a name, called nginx-allow. The pod selector, to identify which pods this rule applies, will be the pod selector / label app:nginx. Click on the Add Label button to save it.

Now we need to add the rule regarding who can have ingress access to Nginx. I changed the From: field to be Selector rather than IP Block, and stated that only pods with the app:nginx label (Pod Selector) can have  ingress access. This should mean that our busybox pod no longer have access to the web-server.

Save the policy by click on the Create Policy button at the bottom. The new rule should now be associated with the namespace.

Step 7 – Test that the network policy is working

To test that the policy is working, try to access the web server from the busybox pod as before.

$ kubectl exec -it busybox -n network-testing -- sh
/ # wget -q -O - 100.67.183.176
wget: can't connect to remote host (100.67.183.176): Connection timed out

It would seem that the policy has successfully taken effect, and we are no longer able to access the web server because our busybox pod does not have the correct pod identifier / label.

Step 8 – Verifying with a different Pod Selector

There are two ways that you could allow the busybox pod to communicate to the web server. The first is to change the label on the busybox pod so that it has a label of app:nginx, or the alternate method is to change the rule in the policy, and modiy the pod selector from app:nginx to app:busybox. If we do the latter, the rule would look similar to the following:

After saving the rule, our wget command from the busybox pod to the web server service should start working again.

/ # wget -q -O - 100.67.183.176 | grep title
<title>Welcome to nginx!</title>

Success! Finally, we can examine the network policy object that was created in our TKG cluster namespace by using the following kubectl commands.

$ kubectl get networkpolicy -A
NAMESPACE        NAME                                  POD-SELECTOR  AGE
network-testing  tmc.wsp.network-testing.nginx-allow  <none>        12m


$ kubectl describe networkpolicy -n network-testing
Name:        tmc.wsp.network-testing.nginx-allow
Namespace:    network-testing
Created on:  2021-11-04 11:57:38 +0000 GMT
Labels:      tmc.cloud.vmware.com/managed=true
Annotations:  <none>
Spec:
  PodSelector:    app=nginx
  Allowing ingress traffic:
    To Port: <any> (traffic allowed to all ports)
    From:
      PodSelector: app=busybox
  Not affecting egress traffic
  Policy Types: Ingress

You can find our more information around rules that can be used in network policies in the official documentation.