CKAD — Security Lab

2 minute read

Lab 1: Running as Non-Root

# Create a Pod running as user 1000
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: non-root-pod
spec:
  securityContext:
    runAsUser: 1000
    runAsNonRoot: true
  containers:
  - name: app
    image: busybox:1.36
    command: ["/bin/sh", "-c", "id && whoami && sleep 3600"]
    securityContext:
      allowPrivilegeEscalation: false
EOF

kubectl logs non-root-pod
# Expected: uid=1000 gid=0(root)
# whoami: unknown uid 1000

Lab 2: ServiceAccount with Limited Permissions

# Create a ServiceAccount
kubectl create serviceaccount limited-sa

# Create a Role that can only list Pods
kubectl create role pod-lister --verb=list --resource=pods

# Bind the Role to the ServiceAccount
kubectl create rolebinding pod-lister-binding \
  --role=pod-lister \
  --serviceaccount=default:limited-sa

# Create a Pod with this ServiceAccount
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: sa-test
spec:
  serviceAccountName: limited-sa
  containers:
  - name: kubectl
    image: bitnami/kubectl:latest
    command: ["/bin/sh", "-c", "sleep 3600"]
EOF

# Test from inside the Pod
kubectl exec sa-test -- kubectl get pods
# Expected: Lists pods successfully

kubectl exec sa-test -- kubectl get secrets
# Expected: Error — forbidden

Practice Questions

Q1: Create a Pod that runs as user ID 1000, group ID 2000, with a read-only root filesystem.

Show Answer ```yaml apiVersion: v1 kind: Pod metadata: name: secure-pod spec: securityContext: runAsUser: 1000 runAsGroup: 2000 containers: - name: app image: busybox:1.36 command: ["/bin/sh", "-c", "id && sleep 3600"] securityContext: readOnlyRootFilesystem: true volumeMounts: - name: tmp mountPath: /tmp volumes: - name: tmp emptyDir: {} ```

Q2: What does allowPrivilegeEscalation: false do?

Show Answer It prevents a process in the container from gaining more privileges than its parent process. This blocks exploits like `setuid` binaries that could allow a non-root process to gain root access. It is a security best practice and should be set to `false` on all production containers.

Q3: Create a ServiceAccount named deploy-sa. Grant it permission to create and delete Deployments in the production namespace.

Show Answer ```bash kubectl create serviceaccount deploy-sa -n production kubectl create role deployment-manager \ --verb=create,delete,get,list \ --resource=deployments \ -n production kubectl create rolebinding deploy-sa-binding \ --role=deployment-manager \ --serviceaccount=production:deploy-sa \ -n production ``` Verify: ```bash kubectl auth can-i create deployments --as=system:serviceaccount:production:deploy-sa -n production # Expected: yes ```

Q4: How do you prevent a Pod from mounting the ServiceAccount token?

Show Answer Set `automountServiceAccountToken: false` at the Pod level or ServiceAccount level: ```yaml # Pod level spec: automountServiceAccountToken: false # Or ServiceAccount level apiVersion: v1 kind: ServiceAccount metadata: name: my-sa automountServiceAccountToken: false ``` This is a security best practice for Pods that do not need to access the Kubernetes API.

Q5: A container needs to bind to port 80 but runs as non-root. Which capability do you add?

Show Answer Add the `NET_BIND_SERVICE` capability: ```yaml securityContext: capabilities: drop: - ALL add: - NET_BIND_SERVICE ``` Ports below 1024 are privileged by default. The `NET_BIND_SERVICE` capability allows non-root processes to bind to these ports without requiring full root privileges.

← Previous: Production Security Next: CRDs & Operators →

Updated: