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
- I’m using minikube with the calico option:
- 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