Please note that the competition status for CKS Challenges is ended. Please do not submit a solution. It will not be scored.
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.
Do the tasks in this order:
-
namespace
All the action is taking place in the
alpha
namespacekubectl config set-context --current --namespace alpha
-
alpha-pv
- A persistentVolume called
alpha-pv
has already been created. Do not modify it. Inspect the parameters used to create it.
kubectl describe pv alpha-pv
Note
StorageClass
,Access Modes
,Capacity
,VolumeMode
- A persistentVolume called
-
alpha-pvc
alpha-pvc
should be bound toalpha-pv
. Delete and Re-create it if necessary.
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
-
images
- Permitted images are:
nginx:alpine
,bitnami/nginx
,nginx:1.13
,nginx:1.17
,nginx:1.16
andnginx:1.14
. Usetrivy
to find the image with the least number ofCRITICAL
vulnerabilities.
-
Inspect all images
docker image ls
Note there are additional images other than those stated
-
Loop over the images we want (by filtering out those we don't), and trivy them getting the information we need
for i in $(docker image ls --format '{{.Repository}}:{{.Tag}}' | grep nginx | grep -v none) do echo -n "$i " trivy i -s CRITICAL $i | grep Total | awk '{print $2}' done
nginx:alpine 0
bitnami/nginx:latest 3
nginx:latest 27
nginx:1.17 43
nginx:1.16 43
nginx:1.14 64
nginx:1.13 85We 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.
- Permitted images are:
-
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.
-
mv /root/usr.sbin.nginx /etc/apparmor.d/usr.sbin.nginx
-
apparmor_parser /etc/apparmor.d/usr.sbin.nginx
- Move the AppArmor profile
-
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 podalpha-xyz
deployment uses thecustom-nginx
apparmor profile (applied to container callednginx
). Note that this task is revealed by clicking the arrow betweencustom-nginx
andalpha-xyz
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 5apiVersion: 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: annotations: container.apparmor.security.beta.kubernetes.io/nginx: localhost/custom-nginx labels: app: alpha-xyz spec: volumes: - name: data-volume persistentVolumeClaim: claimName: alpha-pvc containers: - image: nginx:alpine name: nginx volumeMounts: - name: data-volume mountPath: /usr/share/nginx/html
kubectl apply -f /root/alpha-xyz.yaml
- Create a deployment called
-
alpha-svc
- Expose the
alpha-xyz
as aClusterIP
type service calledalpha-svc
alpha-svc
should be exposed onport: 80
andtargetPort: 80
kubectl expose deployment alpha-xyz --type ClusterIP --name alpha-svc --port 80 --target-port 80
- Expose the
-
restrict-inbound
- Create a NetworkPolicy called
restrict-inbound
in thealpha
namespace - Policy Type =
Ingress
- Inbound access only allowed from the pod called
middleware
with labelapp=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 betweenrestrict-inbound
andalpha-xyz
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
Apply this policy
- Create a NetworkPolicy called
Once all the above tasks are completed, click the Check
button.
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 $(docker image ls --format '{{.Repository}}:{{.Tag}}' | grep nginx | grep -v none)
do
crit=$(trivy i -s CRITICAL $i | grep Total | awk '{print $2}')
[ $crit -lt $vuln ] && vuln=$crit && img=$i
done
# 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:
annotations:
container.apparmor.security.beta.kubernetes.io/nginx: localhost/custom-nginx
labels:
app: alpha-xyz
spec:
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: alpha-pvc
containers:
- image: $img
name: 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"
}