7 minute read

In our previous post on Kubernetes Networking with Calico CNI we looked into Calico CNI implemenation of Kubernetes networking and also we looked at an example network policy. In this post, let us take a look at another example of Kubernetes Network Policy.

To test the networking policy, let us create a simple deployment and expose it as a service.

pradeep@learnk8s$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
pradeep@learnk8s$ kubectl expose deployment nginx --port=80
service/nginx exposed
pradeep@learnk8s$ kubectl get all -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
pod/nginx-85b98978db-p4r8c   1/1     Running   0          28s   172.17.0.3   minikube   <none>           <none>

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service/kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP   11h   <none>
service/nginx        ClusterIP   10.102.7.79   <none>        80/TCP    17s   app=nginx

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
deployment.apps/nginx   1/1     1            1           28s   nginx        nginx    app=nginx

NAME                               DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES   SELECTOR
replicaset.apps/nginx-85b98978db   1         1         1       28s   nginx        nginx    app=nginx,pod-template-hash=85b98978db
pradeep@learnk8s$ 

Now that a service is created, test it by accessing it from another Pod.

Create a Pod from busybox and launch the shell.

pradeep@learnk8s$ kubectl run busybox --rm -ti --image=busybox:1.28 -- /bin/sh 
If you don't see a command prompt, try pressing enter.
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ #

Use wget --spider command to test the access to our initigial nginx pod service.

/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.102.7.79:80)
/ # ping nginx
PING nginx (10.102.7.79): 56 data bytes
^C
--- nginx ping statistics ---
7 packets transmitted, 0 packets received, 100% packet loss

While wget --spider does not download any files, test it again without the --spider option.

/ # cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
fe00::0	ip6-mcastprefix
fe00::1	ip6-allnodes
fe00::2	ip6-allrouters
172.17.0.4	busybox
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.102.7.79:80)
/ # wget nginx
Connecting to nginx (10.102.7.79:80)
index.html           100% |********************************************************|   615   0:00:00 ETA
/ # ls
bin         etc         index.html  root        tmp         var
dev         home        proc        sys         usr
/ # 

We can see that both Pods can communicate with each other, that is by default allowed.

Exit the busybox pod.

/ # exit
Session ended, resume using 'kubectl attach busybox -c busybox -i -t' command when the pod is running
pod "busybox" deleted

Exiting should cause the busybox Pod to be deleted also, because of the additional flags we have provided with the kubectl run command earlier.

pradeep@learnk8s$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nginx-85b98978db-p4r8c   1/1     Running   0          7m46s
pradeep@learnk8s$ 

Now, let us limit this access by creating a Network Policy.

First verify if we have any network policies currently.

pradeep@learnk8s$ kubectl get netpol
No resources found in default namespace.

To limit the access to the nginx service so that only Pods with the label access: true can query it, create a NetworkPolicy object as follows:

pradeep@learnk8s$ cat nginx-policy.yaml 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      app: nginx
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"
pradeep@learnk8s$ kubectl create -f nginx-policy.yaml 
networkpolicy.networking.k8s.io/access-nginx created
pradeep@learnk8s$ kubectl get netpol
NAME           POD-SELECTOR   AGE
access-nginx   app=nginx      4s

Describe our network policy

pradeep@learnk8s$ kubectl describe netpol
Name:         access-nginx
Namespace:    default
Created on:   2022-04-23 17:23:57 +0530 IST
Labels:       <none>
Annotations:  <none>
Spec:
  PodSelector:     app=nginx
  Allowing ingress traffic:
    To Port: <any> (traffic allowed to all ports)
    From:
      PodSelector: access=true
  Not affecting egress traffic
  Policy Types: Ingress
pradeep@learnk8s$ 

NetworkPolicy includes a podSelector which selects the grouping of Pods to which the policy applies. You can see this policy selects Pods with the label app=nginx. The label was automatically added to the Pod in the nginx Deployment. An empty podSelector selects all pods in the namespace.

Test access to the service when access=true label is not defined.

pradeep@learnk8s$ kubectl run busybox --rm -ti --image=busybox:1.28 -- /bin/sh

If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.102.7.79:80)
/ # wget nginx
Connecting to nginx (10.102.7.79:80)
index.html           100% |********************************************************|   615   0:00:00 ETA
/ # 

We can see that, though we do not have the required label as per our current network policy definition, the pods are able to communicate with each other.

This is because our current network provider does not support the network policies. We started our minikube cluster with defaults, which does not support network policies.

pradeep@learnk8s$ minikube start 
😄  minikube v1.25.2 on Darwin 12.2.1
✨  Automatically selected the hyperkit driver
👍  Starting control plane node minikube in cluster minikube
🔥  Creating hyperkit VM (CPUs=2, Memory=2200MB, Disk=20000MB) ...
🐳  Preparing Kubernetes v1.23.3 on Docker 20.10.12 ...
    ▪ kubelet.housekeeping-interval=5m
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
pradeep@learnk8s$ kubectl get pods -A
NAMESPACE     NAME                               READY   STATUS    RESTARTS       AGE
default       nginx-85b98978db-p4r8c             1/1     Running   0              18m
kube-system   coredns-64897985d-srqsj            1/1     Running   5 (78m ago)    11h
kube-system   etcd-minikube                      1/1     Running   3 (78m ago)    11h
kube-system   kube-apiserver-minikube            1/1     Running   12             11h
kube-system   kube-controller-manager-minikube   1/1     Running   14 (72m ago)   11h
kube-system   kube-proxy-bsbvb                   1/1     Running   0              11h
kube-system   kube-scheduler-minikube            1/1     Running   5              11h
kube-system   storage-provisioner                1/1     Running   20 (33m ago)   11h
pradeep@learnk8s$

Let us stop and delete this cluster and launch it again with Calico CNI.

pradeep@learnk8s$ minikube stop
✋  Stopping node "minikube"  ...
🛑  1 node stopped.
pradeep@learnk8s$ minikube delete
🔥  Deleting "minikube" in hyperkit ...
💀  Removed all traces of the "minikube" cluster.
pradeep@learnk8s$ 
pradeep@learnk8s$ minikube start --cni=calico
😄  minikube v1.25.2 on Darwin 12.2.1
✨  Automatically selected the docker driver. Other choices: hyperkit, ssh
👍  Starting control plane node minikube in cluster minikube
🚜  Pulling base image ...
    > gcr.io/k8s-minikube/kicbase: 379.06 MiB / 379.06 MiB  100.00% 3.06 MiB p/
🔥  Creating docker container (CPUs=2, Memory=2200MB) ...
🐳  Preparing Kubernetes v1.23.3 on Docker 20.10.12 ...
    ▪ kubelet.housekeeping-interval=5m
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring Calico (Container Networking Interface) ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: default-storageclass, storage-provisioner
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
pradeep@learnk8s$ 

Look at the line Configuring Calico (Container Networking Interface) ...

pradeep@learnk8s$ kubectl get pods -A
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-8594699699-npmdd   0/1     Running   0          3m7s
kube-system   calico-node-dk4f5                          1/1     Running   0          3m7s
kube-system   coredns-64897985d-qlzt6                    1/1     Running   0          3m7s
kube-system   etcd-minikube                              1/1     Running   0          3m18s
kube-system   kube-apiserver-minikube                    1/1     Running   0          3m18s
kube-system   kube-controller-manager-minikube           1/1     Running   0          3m18s
kube-system   kube-proxy-kzh2x                           1/1     Running   0          3m7s
kube-system   kube-scheduler-minikube                    1/1     Running   0          3m18s
kube-system   storage-provisioner                        1/1     Running   0          2m58s
pradeep@learnk8s$ 

As it is a new cluster, all of our previous work has gone! Let us build those two Pods and service once again quickly.

pradeep@learnk8s$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
pradeep@learnk8s$ kubectl expose deployment nginx --port=80
service/nginx exposed

Get all the resources with their labels.

pradeep@learnk8s$ kubectl get all --show-labels
NAME                         READY   STATUS    RESTARTS   AGE     LABELS
pod/nginx-85b98978db-t44nc   1/1     Running   0          4m32s   app=nginx,pod-template-hash=85b98978db

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     LABELS
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   21m     component=apiserver,provider=kubernetes
service/nginx        ClusterIP   10.96.213.189   <none>        80/TCP    4m23s   app=nginx

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE     LABELS
deployment.apps/nginx   1/1     1            1           4m32s   app=nginx

NAME                               DESIRED   CURRENT   READY   AGE     LABELS
replicaset.apps/nginx-85b98978db   1         1         1       4m32s   app=nginx,pod-template-hash=85b98978db
pradeep@learnk8s$ 
pradeep@learnk8s$ kubectl describe service nginx
Name:              nginx
Namespace:         default
Labels:            app=nginx
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.213.189
IPs:               10.96.213.189
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.120.67:80
Session Affinity:  None
Events:            <none>

Apply the network policy.

pradeep@learnk8s$ kubectl create -f nginx-policy.yaml 
networkpolicy.networking.k8s.io/access-nginx created
pradeep@learnk8s$ kubectl describe netpol
Name:         access-nginx
Namespace:    default
Created on:   2022-04-23 17:58:00 +0530 IST
Labels:       <none>
Annotations:  <none>
Spec:
  PodSelector:     app=nginx
  Allowing ingress traffic:
    To Port: <any> (traffic allowed to all ports)
    From:
      PodSelector: access=true
  Not affecting egress traffic
  Policy Types: Ingress
pradeep@learnk8s$ 

Test now without the required matching labels applied.

pradeep@learnk8s$ kubectl run busybox --rm -ti --image=busybox:1.28 -- /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.96.213.189:80)
wget: download timed out
/ # wget nginx --timeout=1
Connecting to nginx (10.96.213.189:80)
wget: download timed out
/ # 

The network policy seems to be working.

Exit out of this Pod, and create a new pod, this time with matching labels.

/ # exit
Session ended, resume using 'kubectl attach busybox -c busybox -i -t' command when the pod is running
pod "busybox" deleted
pradeep@learnk8s$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox:1.28 -- /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.96.213.189:80)
/ # wget nginx
Connecting to nginx (10.96.213.189:80)
index.html           100% |********************************************************|   615   0:00:00 ETA
/ # exit
Session ended, resume using 'kubectl attach busybox -c busybox -i -t' command when the pod is running
pod "busybox" deleted
pradeep@learnk8s$ 

This concludes our testing of a simple Kubernetes Network policy.

Back to Top ↑