Skip to content

Latest commit

 

History

History
377 lines (291 loc) · 10 KB

File metadata and controls

377 lines (291 loc) · 10 KB

CKS Challenge 1

Take me to the lab!

Please note that the competition status for CKS Challenges is ended. Please do not submit a solution. It will not be scored.

Challenge

There are 6 images listed in the diagram. Using Aquasec Trivy (which is already installed on the controlplane node), identify the image that has the least number of critical vulnerabilities and use it to deploy the alpha-xyz deployment.

Secure this deployment by enforcing the AppArmor profile called custom-nginx.

Expose this deployment with a ClusterIP type service and make sure that only incoming connections from the pod called middleware is accepted and everything else is rejected.

Click on each icon (in the lab) to see more details. Once done, click the Check button to test your work.

Diagram

Do the tasks in this order:

  1. namespace

    All the action is taking place in the alpha namespace

    kubectl config set-context --current --namespace alpha
    
  2. alpha-pv
    • A persistentVolume called alpha-pv has already been created. Do not modify it. Inspect the parameters used to create it.
    Reveal
    kubectl describe pv alpha-pv

    Note StorageClass, Access Modes, Capacity, VolumeMode

  3. alpha-pvc
    • alpha-pvc should be bound to alpha-pv. Delete and Re-create it if necessary.
    Reveal
    kubectl get pvc alpha-pvc
    

    Status is pending, i.e it wont bind.

    Delete the PVC and recreate it with values for storage class, access modes and capacity matching those of the PV

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: alpha-pvc
      namespace: alpha
    spec:
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
      storageClassName: local-storage
      volumeMode: Filesystem
  4. images
    • Permitted images are: docker.io/library/nginx:alpine, docker.io/bitnami/nginx, docker.io/library/nginx:1.13, docker.io/library/nginx:1.17, docker.io/library/nginx:1.16 and docker.io/library/nginx:1.14. Use trivy to find the image with the least number of CRITICAL vulnerabilities.
    Reveal
    1. Inspect all images

      crictl image ls
      

      Note there are additional images other than those stated

    2. Loop over the images we want (by filtering out those we don't), and trivy them getting the information we need

      for i in $(crictl image -f reference=nginx -o json | jq -r .images[].repoTags[] | grep -v "docker.io/library/nginx:latest")
      do
          echo -n "$i "
          trivy i -s CRITICAL $i 2>&1 | grep Total | awk '{print $2}'
      done

      We can see that nginx:alpine has the least (zero) criticals, which is kind of as expected! We will use this image when we come to deploy the pod later.

  5. custom-nginx
    • Move the AppArmor profile /root/usr.sbin.nginx to /etc/apparmor.d/usr.sbin.nginx on the controlplane node
    • Load the AppArmor profile called custom-nginx and ensure it is enforced.
    Reveal
    1. mv /root/usr.sbin.nginx /etc/apparmor.d/usr.sbin.nginx
    2. apparmor_parser /etc/apparmor.d/usr.sbin.nginx
  6. alpha-xyz
    • Create a deployment called alpha-xyz that uses the image with the least 'CRITICAL' vulnerabilities? (Use the sample YAML file located at /root/alpha-xyz.yaml to create the deployment. Please make sure to use the same names and labels specified in this sample YAML file!)
    • Deployment has exactly 1 ready replica
    • data-volume is mounted at /usr/share/nginx/html on the pod
    • alpha-xyz deployment uses the custom-nginx apparmor profile (applied to container called nginx). Note that this task is revealed by clicking the arrow between custom-nginx and alpha-xyz
    Reveal

    Edit the given file /root/alpha-xyz.yaml and fill in the necessary properties. We need to use the PVC from step 3, the image determined in step 4 and the apparmor profile from step 5

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      creationTimestamp: null
      labels:
        app: alpha-xyz
      name: alpha-xyz
      namespace: alpha
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: alpha-xyz
      strategy: {}
      template:
        metadata:
          labels:
            app: alpha-xyz
        spec:
          volumes:
          - name: data-volume
            persistentVolumeClaim:
              claimName: alpha-pvc
          containers:
          - image: nginx:alpine
            name: nginx
            securityContext:
              appArmorProfile:
                type: Localhost
                localhostProfile: custom-nginx
            volumeMounts:
            - name: data-volume
              mountPath: /usr/share/nginx/html
    kubectl apply -f /root/alpha-xyz.yaml
  7. alpha-svc
    • Expose the alpha-xyz as a ClusterIP type service called alpha-svc
    • alpha-svc should be exposed on port: 80 and targetPort: 80
    Reveal
    kubectl expose deployment alpha-xyz --type ClusterIP --name alpha-svc --port 80 --target-port 80
  8. restrict-inbound
    • Create a NetworkPolicy called restrict-inbound in the alpha namespace
    • Policy Type = Ingress
    • Inbound access only allowed from the pod called middleware with label app=middleware
    • Inbound access only allowed to TCP port 80 on pods matching the policy
    • Policy should be only applied on pods with label app=alpha-xyz. This task is revealed by clicking the arrow between restrict-inbound and alpha-xyz
    Reveal
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: restrict-inbound
      namespace: alpha
    spec:
      podSelector:                  # Policy should be only applied on pods with label app=alpha-xyz
        matchLabels:
          app: alpha-xyz
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:          # Inbound access only allowed from the pod called middleware with label app=middleware
                matchLabels:
                  app: middleware
          ports:                    # Inbound access only allowed to TCP port 80 on pods matching the policy
            - port: 80

    Apply this policy

Once all the above tasks are completed, click the Check button.

Automate the lab in a single script!

As DevOps engineers, we love everything to be automated!

Automation Script

Paste this entire script to the lab terminal, sit back and enjoy!
When the script completes, you can press the Check button and the lab will be complete!

# CKS challenge 1
{
start_time=$(date '+%s')

# Set namespace
kubectl config set-context --current --namespace alpha

# Fix PVC
kubectl delete pvc alpha-pvc

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: alpha-pvc
  namespace: alpha
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: local-storage
  volumeMode: Filesystem
EOF

kubectl wait --for=jsonpath='{.status.phase}'=Bound pvc/alpha-pvc --timeout=30s

# Find image with least vulnerabilites
img=''
vuln=10000

for i in $(crictl image -f reference=nginx -o json | jq -r .images[].repoTags[] | grep -v "docker.io/library/nginx:latest")
do
    echo "Trivy - $i"
    crit=$(trivy i -s CRITICAL $i  2>&1 | grep Total | awk '{print $2}')
    [ $crit -lt $vuln ] && vuln=$crit && img=$i
done

echo "$img - $vuln critical."

# Set up apparmor
mv /root/usr.sbin.nginx /etc/apparmor.d/usr.sbin.nginx
apparmor_parser /etc/apparmor.d/usr.sbin.nginx

# Create deployment with selected image

cat << EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: alpha-xyz
  name: alpha-xyz
  namespace: alpha
spec:
  replicas: 1
  selector:
    matchLabels:
      app: alpha-xyz
  strategy: {}
  template:
    metadata:
      labels:
        app: alpha-xyz
    spec:
      volumes:
      - name: data-volume
        persistentVolumeClaim:
          claimName: alpha-pvc
      containers:
      - image: $img
        name: nginx
        securityContext:
          appArmorProfile:
            type: Localhost
            localhostProfile: custom-nginx
        volumeMounts:
        - name: data-volume
          mountPath: /usr/share/nginx/html
EOF

kubectl wait deployment -n alpha alpha-xyz --for condition=Available=True --timeout=30s

# Expose deployment
kubectl expose deployment alpha-xyz --type ClusterIP --name alpha-svc --port 80 --target-port 80

# Create netpol
cat << EOF | kubectl create -f -

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: restrict-inbound
  namespace: alpha
spec:
  podSelector:
    matchLabels:
      app: alpha-xyz
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: middleware
      ports:
        - port: 80
EOF

end_time=$(date '+%s')
duration=$(( end_time - start_time ))
echo "Complete in ${duration}s"

}