---
title: 'CKA Practice: Configure Network Policies To Restrict Traffic Between Pods'

description: |
  This exercise tests your ability to configure kubernetes network policies to make sure only pods with specific labels can communicate with each other.

kind: challenge

playground: k3s

playgroundOptions:
  tabs:
  - machine: dev-machine
  - machine: cplane-01
  - machine: node-01

  machines:
    - name: dev-machine
      users:
      - name: root
        default: true
        welcome: |
          Welcome to the CKA networking exercise.

          Follow the instructions to configure secure pod communication.
    - name: cplane-01
    - name: node-01

cover: __static__/pod-networking-with-labels.png

createdAt: 2024-11-03
updatedAt: 2024-12-18

difficulty: easy

categories:
  - kubernetes
  - networking

tagz:
  - cka
  - network-policies

tasks:
  verify_namespace:
    run: |
      if [ $(kubectl get namespace | grep app | wc -l) -gt 0 ]; then
        echo "Namespace created!"
        exit 0
      else
        exit 1
      fi
  verify_deployment_frontend:
    needs:
      - verify_namespace
    run: |
      if [ $(kubectl get deployment -n app frontend -o jsonpath='{.status.replicas}') -eq 2 ]; then
         echo "Frontend deployment created successfully!"
         exit 0
      else
         exit 1
      fi
  verify_deployment_backend:
    needs:
      - verify_namespace
    run: |
      if [ $(kubectl get deployment -n app backend -o jsonpath='{.status.replicas}') -eq 2 ]; then
         echo "Backend deploymenet created successfully!"
         exit 0
      else
         exit 1
      fi
  verify_labels_all_frontend:
    needs:
      - verify_deployment_frontend
      - verify_deployment_backend
    run: |
      if [ $(kubectl get pods -n app -l role=frontend --no-headers | wc -l) -eq 2 ]; then
         echo "Frontend pod labels configured correctly!"
         exit 0
      else
         exit 1
      fi
  verify_labels_all_backend:
    needs:
      - verify_deployment_frontend
      - verify_deployment_backend
    run: |
      if [ $(kubectl get pods -n app -l tier=api --no-headers | wc -l) -eq 2 ]; then
         echo "Backend pod labels configured correctly!"
         exit 0
      else
         exit 1
      fi
  verify_labels_one_backend:
    needs:
      - verify_deployment_frontend
      - verify_deployment_backend
    run: |
      if [ $(kubectl get pods -n app -l "tier=api,!role" --no-headers | wc -l) -eq 1 ]; then
         echo "Single backend pod label configured correctly!"
         exit 0
      else
         exit 1
      fi
  verify_network_policies:
    # we don't want this to start firing too soon
    needs:
      - verify_labels_all_frontend
      - verify_labels_all_backend
      - verify_labels_one_backend
    # default timeout is 10-15 seconds, and we want the checking loop to run faster than that
    timeout_seconds: 7
    run: |
      # Get a frontend pod and one backend pod with role=backend and one backend pod without a role
      FRONTEND_POD=$(kubectl get pod -n app -l role=frontend -o jsonpath='{.items[0].metadata.name}')
      FRONTEND_POD_IP=$(kubectl get pod -n app -l role=frontend -o jsonpath='{.items[0].status.podIP}')

      BACKEND_POD_WITH_ROLE=$(kubectl get pod -n app -l role=backend -o jsonpath='{.items[0].metadata.name}')
      BACKEND_POD_WITH_ROLE_IP=$(kubectl get pod -n app -l role=backend -o jsonpath='{.items[0].status.podIP}')

      BACKEND_POD_WITHOUT_ROLE=$(kubectl get pod -n app -l "tier=api,role!=backend" -o jsonpath='{.items[0].metadata.name}')
      BACKEND_POD_WITHOUT_ROLE_IP=$(kubectl get pod -n app -l "tier=api,role!=backend" -o jsonpath='{.items[0].status.podIP}')

      # Test connectivity from frontend to both backend pods
      FRONTEND_TO_BACKEND=$(kubectl -n app exec $FRONTEND_POD -- curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 $BACKEND_POD_WITH_ROLE_IP:8000)
      FRONTEND_TO_BACKEND_WITHOUT_ROLE=$(kubectl -n app exec $FRONTEND_POD -- curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 $BACKEND_POD_WITHOUT_ROLE_IP:8000)

      # Test connectivity from both types of backend pods to frontend pod
      BACKEND_WITH_ROLE_TO_FRONTEND=$(kubectl -n app exec $BACKEND_POD_WITH_ROLE -- curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 $FRONTEND_POD_IP:80)

      BACKEND_WITHOUT_ROLE_TO_FRONTEND=$(kubectl exec -n app $BACKEND_POD_WITHOUT_ROLE -- curl -s --connect-timeout 5 $FRONTEND_POD_IP:80 2>&1 || true)

      if [ "$FRONTEND_TO_BACKEND" -eq 200 ] && \
         [ "$FRONTEND_TO_BACKEND_WITHOUT_ROLE" -eq 200 ] && \
         [ "$BACKEND_WITH_ROLE_TO_FRONTEND" -eq 200 ] && \
         [[ "$BACKEND_WITHOUT_ROLE_TO_FRONTEND" == *"command terminated"* ]]; then
         echo "Network policies configured correctly!"
         exit 0
      else
        exit 1
      fi

---

In this exercise, you will configure network policies to control traffic flow between two deployments in a Kubernetes cluster. You'll need to ensure specific pods can communicate based on their labels while blocking unauthorized traffic. Have fun!

<img src="__static__/pod-networking-with-labels.png" style="margin: 0px auto; max-width: 600px; width: 100%" alt="Diagram showing desired network policy configuration between frontend and backend pods">

First, create a namespace called "app":

::simple-task
---
:tasks: tasks
:name: verify_namespace
---
#active
Waiting for namespace to be created...

#completed
Good, the namespace is ready to go.
::


::hint-box
---
:summary: Hint 1
---
Check the [documentation for creating namespaces](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-namespace-em-)
::

Now, create two deployments in that namespace.


1. Frontend:
   - Deployment "frontend" with 2 replicas running `ghcr.io/iximiuz/labs/nginx:alpine`
   - Accessible on port 80
2. Backend:
   - Deployment "backend" with 2 replicas running `ghcr.io/lpmi-13/default-go`
   - Accessible on port 8000

::simple-task
---
:tasks: tasks
:name: verify_deployment_frontend
---
#active
Waiting for frontend deployment to be created...

#completed
Great! Frontend deployment is running correctly.
::

::simple-task
---
:tasks: tasks
:name: verify_deployment_backend
---
#active
Waiting for backend deployment to be created...

#completed
Alright! Backend deployment is running correctly.
::

::hint-box
---
:summary: Hint 2
---
Check the [documentation for creating deployments](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-deployment-em-)
::

Now, label the pods:
1. All frontend pods should have: `role=frontend`
2. All backend pods should have: `tier=api`
3. Only one backend pod should have the additional label: `role=backend`

::simple-task
---
:tasks: tasks
:name: verify_labels_all_frontend
---
#active
Checking for correct frontend pod labels...

#completed
Nice! Both frontend pods are properly labeled with `role=frontend`.
::

::simple-task
---
:tasks: tasks
:name: verify_labels_all_backend
---
#active
Checking for correct backend pod labels...

#completed
Fantastic! Both backend pods are properly labeled with `tier=api`.
::

::simple-task
---
:tasks: tasks
:name: verify_labels_one_backend
---
#active
Checking for correct backend pod label...

#completed
Good! Only one backend pod is properly labeled with `role=backend`.
::

::hint-box
---
:summary: Hint 3
---
Check the [documentation for adding labels](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#label)
::

::hint-box
---
:summary: Hint 4
---
```bash
# Get the name of one backend pod
BACKEND_POD=$(kubectl get pods -n app -l app=backend -o jsonpath='{.items[0].metadata.name}')
```
::

Finally, create network policies to make sure:
1. All frontend pods can send traffic to any backend pod with label `tier=api` on port 8000
2. Only the backend pod with label `role=backend` can send traffic to frontend pods with label `role=frontend` on port 80
3. All other traffic should be denied by default

::simple-task
---
:tasks: tasks
:name: verify_network_policies
---
#active
Verifying network policies and testing connectivity...

#completed
Excellent! The network policies are correctly configured and enforcing the desired traffic patterns.
::

::hint-box
---
:summary: Hint 5
---
Create two network policies, one for the frontend => backend, and another from the backend => frontend. Here's the first one:
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-to-backend
  namespace: app
spec:
  podSelector:
    matchLabels:
      tier: api
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - port: 8000
      protocol: TCP
```
::