Menu Close

CKA Exam Task: Create Network Policy

In the Certified Kubernetes Administrator (CKA) exam, you might be asked to Create a Network Policy in your Kubernetes cluster. This post shows how to do it.

Example Exam Task: Create Network Policy

Create a network policy in the namespace webserver named webserver-policy.

The network policy should allow:

  • TCP using port 80 from pods in the namespace internal-client
  • TCP using port 80 from pods in the same namespace

Assign the policy to all pods in the namespace.

Furthermore, ensure that Pods in the namespace webserver can only connect to other pods in the same namespace using TCP on port 80.

You can use existing Pods in the namespaces webserver, internal-client and external-client to verify your policy.

Prerequisites

  • A Kubernetes cluster with a Network Plugin enabling Ingress and Egress Network Policy
    • I’m using minikube with the calico option: minikube start --cni calico
  • Kubectl installed and configured to access the Kubernetes cluster with administrator rights
  • Run the following script to prepare your Kubernetes cluster for this exercise:
#!/bin/bash

kubectl create ns webserver
kubectl create ns internal-client
kubectl create ns external-client

kubectl run -n webserver webserver1 --image nginx
kubectl run -n webserver webserver2 --image nginx

kubectl run -n internal-client client1 --image busybox -- sh -c "while true; do echo Running; sleep 1; done;"
kubectl run -n external-client client2 --image busybox -- sh -c "while true; do echo Running; sleep 1; done;"

Create Network Policy

You can’t create a boilerplate Network Policy through kubectl create --dry-run=client -o yaml. Thus the best way to get boilerplate code is by copying & pasting from the Kubernetes docs. Then start editing the yaml manifest as required by the task. A good point to start is this part of the documentation.

We will copy the yaml from this section to a new file and delete all the rules so that we end up with a clean boilerplate for our Network Policy:

๐Ÿค“: Quickly delete lines during the exam by using the vim shortcuts. Use 'dd' to delete a single line or 'dXd' to delete X lines, with X being an integer.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
    - Ingress
    - Egress
  ingress:
  egress:

In this task, it is crucial to carefully read the description and extract the required information. First, make sure the name and namespace field matches the task description:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: webserver-policy
  namespace: webserver
...

Then look for the pods this policy should apply to, which are all in the namespace. You can configure this by using an empty pod selector. So change the file accordingly:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: webserver-policy
  namespace: webserver
spec:
  podSelector: {}
...

Next, we need to figure out what policyTypes we should use for the Network Policy. Possible types are Ingress, Egress, or both. You can figure this out by looking for keywords like “from” and “to” in the description. In this task, we need both which indicates we should define both types. So we don’t have to change anything in our manifest

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: webserver-policy
  namespace: webserver
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
...

Now let’s define the actual ingress rules for the policy by looking for the keyword “from” in the description. We have two matches:

  • TCP using port 80 from pods in the namespace internal-client
  • TCP using port 80 from pods in the same namespace

So let’s add a from rule that satisfies the requirements:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: webserver-policy
  namespace: webserver
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: internal-client
      - podSelector: {}
      ports:
        - protocol: TCP
          port: 80      
๐Ÿค“: You can't use namespaces names in the namespaceSelector. Fortunately, in recent Kubernetes versions, the kubernetes.io/metadata.name label is added to every namespace by default.

The only thing left is adding the required Egress rules. Usually, the keyword “to” indicates those rules in the exam task description.

  • Furthermore, ensure that Pods in the namespace webserver can only connect to other pods in the same namespace using TCP on port 80.

So let’s also add this rule and we have our entire NetworkPolicy manifest for this task:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: webserver-policy
  namespace: webserver
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: internal-client
      - podSelector: {}
      ports:
        - protocol: TCP
          port: 80       
  egress:
    - to:
      - podSelector: {}
      ports:
        - protocol: TCP
          port: 80

Apply the policy by running kubectl apply -f network-policy.yaml.

Verify Network Policy

After you’ve applied the Network Policy, you can verify that it’s working by executing commands in the pods already existing in the cluster:

# Get IP of pods
kubectl get pods -n webserver -o wide
NAME         READY   STATUS    RESTARTS        AGE   IP              NODE       NOMINATED NODE   READINESS GATES
webserver1   1/1     Running   2 (6m36s ago)   25h   10.244.120.72   minikube   <none>           <none>
webserver2   1/1     Running   2 (6m36s ago)   25h   10.244.120.73   minikube   <none>           <none>

kubectl get pods -n internal-client -o wide
NAME      READY   STATUS    RESTARTS        AGE   IP              NODE       NOMINATED NODE   READINESS GATES
client1   1/1     Running   2 (9m19s ago)   25h   10.244.120.76   minikube   <none>           <none>

kubectl get pods -n external-client -o wide
NAME      READY   STATUS    RESTARTS      AGE   IP              NODE       NOMINATED NODE   READINESS GATES
client2   1/1     Running   2 (10m ago)   25h   10.244.120.71   minikube   <none>           <none>

# Using curl/wget based on what the nginx/busybox image provide
kubectl exec -n webserver webserver1 -- curl 10.244.120.73:80 # Port 80 from webserver1 to webserver2 should work
kubectl exec -n webserver webserver2 -- curl 10.244.120.72:80 # Port 80 from webserver2 to webserver1 should work
kubectl exec -n webserver webserver2 -- curl 10.244.120.72:8080 # Other ports from webserver2 to webserver1 should fail

kubectl exec -n internal-client client1 -- wget -O- 10.244.120.72:80 # port 80 from internal-client to webserver1 should work
kubectl exec -n internal-client client1 -- wget -O- 10.244.120.73:80 # port 80 from internal-client to webserver2 should work
kubectl exec -n internal-client client1 -- wget -O- 10.244.120.73:8080 # other port from internal-client to webserver2 should fail

# All requests from external-client to webserver should fail
kubectl exec -n external-client client2 -- wget -O- 10.244.120.72:80
kubectl exec -n external-client client2 -- wget -O- 10.244.120.73:8080

Conclusion

In this post you’ve learned:

  • How to analyze an example exam task for NetworkPolicy requirements
  • How to create a NetworkPolicy with Ingress and Egress rules
  • How to apply that NetworkPolicy to all pods in a specific namespace
  • How to verify that NetworkPolicy is enforced

Don’t want to miss the next post in the Certified Kubernetes Administrator (CKA) series? Follow me on LinkedIn!

To support my efforts use my affiliate link to buy your courses and exams from the Linux Foundation.

Previous post in the CKA series: CKA Exam Task: Backup and Restore etcd

Next post in the CKA series: CKA Exam Tasks: Kubernetes Deployments