Mock exams · Mock paper A — the six domains in order
Answers — Mock paper A — the six domains in order
One answer per task, numbered like the paper. Commands assume a RHEL 10 system; check the result before you move on.
Marking notes
6 points per task: 3 for the object existing with the right values, 3 for it
actually working. A task that "looks right" but was applied on the wrong node
scores zero.
Task 1
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: default-deny, namespace: prod}
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: allow-dns, namespace: prod}
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to: [{namespaceSelector: {}}]
ports:
- {protocol: UDP, port: 53}
- {protocol: TCP, port: 53}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: frontend-to-backend, namespace: prod}
spec:
podSelector: {matchLabels: {tier: backend}}
policyTypes: [Ingress]
ingress:
- from: [{podSelector: {matchLabels: {tier: frontend}}}]
ports: [{protocol: TCP, port: 3000}]
Verify: kubectl exec -n prod deploy/frontend -- wget -qO- http://backend:3000
succeeds; the same from any other Pod times out.
Task 2
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: block-imds, namespace: prod}
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to: [{ipBlock: {cidr: 0.0.0.0/0, except: ["169.254.169.254/32"]}}]
- to: [{namespaceSelector: {}}]
ports: [{protocol: UDP, port: 53}, {protocol: TCP, port: 53}]
Verify: curl -m2 http://169.254.169.254/ times out from inside a Pod.
Task 3
# /etc/kubernetes/manifests/kube-apiserver.yaml
- --anonymous-auth=false
- --profiling=false
sleep 20 && kubectl get --raw /healthz
Backup first: cp kube-apiserver.yaml /root/apiserver.bak. If the API server does
not return, crictl logs the container and fix the YAML.
Task 4
openssl req -x509 -nodes -newkey rsa:2048 -days 365 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=shop.example.com"
kubectl create secret tls shop-tls --cert=/tmp/tls.crt --key=/tmp/tls.key -n shop
kubectl create ingress shop --class=nginx --rule="shop.example.com/*=shop:80,tls=shop-tls" -n shop
Verify: kubectl describe ingress shop -n shop shows the host and the secret.
Task 5
curl -sLO https://dl.k8s.io/v1.35.0/bin/linux/amd64/kubelet.sha256
echo "$(cat kubelet.sha256) /usr/local/bin/kubelet" | sha256sum --check
OK → echo ok > /root/kubelet-check.txt; FAILED → echo tampered > ….
Task 6
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: {name: jane-reader, namespace: prod}
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: {name: jane-reader, namespace: prod}
subjects: [{kind: User, name: jane, apiGroup: rbac.authorization.k8s.io}]
roleRef: {kind: Role, name: jane-reader, apiGroup: rbac.authorization.k8s.io}
Verify all four directions with kubectl auth can-i.
Task 7
kubectl patch sa api -n prod -p '{"automountServiceAccountToken": false}'
kubectl patch deployment client -n prod --type=strategic -p \
'{"spec":{"template":{"spec":{"automountServiceAccountToken":false}}}}'
kubectl rollout status deployment/client -n prod
Verify the token file is absent inside the Pod.
Task 8
- --enable-admission-plugins=NodeRestriction
- --authorization-mode=Node,RBAC
Verify with ps -ef | grep kube-apiserver (the flags must be visible) andkubectl get --raw /healthz.
Task 9
sudo tee /etc/apparmor.d/deny-write >/dev/null <<'EOF'
#include <tunables/global>
profile deny-write flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
file,
deny /tmp/** w,
}
EOF
sudo apparmor_parser -r /etc/apparmor.d/deny-write
securityContext:
appArmorProfile: {type: Localhost, localhostProfile: deny-write}
Verify cat /proc/self/attr/current inside the Pod prints deny-write.
Task 10
{"defaultAction":"SCMP_ACT_ALLOW",
"architectures":["SCMP_ARCH_X86_64","SCMP_ARCH_X86","SCMP_ARCH_X32"],
"syscalls":[{"names":["mkdir","mkdirat"],"action":"SCMP_ACT_ERRNO"}]}
At /var/lib/kubelet/seccomp/profiles/mkdir-deny.json, referenced aslocalhostProfile: profiles/mkdir-deny.json. Verify mkdir fails and/proc/self/status shows Seccomp: 2.
Task 11
The five container-level fields plus runAsNonRoot/runAsUser: 101, and the twoemptyDir mounts nginx needs (/var/cache/nginx, /var/run). Verify Running
after 60 s and that touch /x fails.
Task 12
kubectl label ns locked pod-security.kubernetes.io/enforce=restricted --overwrite
kubectl apply -f bad.yaml --dry-run=server
Then fix the Pod template until the server-side dry run passes: non-root,allowPrivilegeEscalation: false, drop: ["ALL"], seccompProfile: RuntimeDefault.
Task 13
EncryptionConfiguration with aescbc first and identity second, mounted into
the API server as a hostPath plus --encryption-provider-config, thenkubectl get secrets -A -o json | kubectl replace -f -. Proof:
sudo ETCDCTL_API=3 etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
--cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key \
get /registry/secrets/default/<name> | strings | head -1
# k8s:enc:aescbc:v1:key1
Task 14
kubectl get pods -n prod -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.spec.containers[*].image}{"\n"}{end}'
trivy image --severity CRITICAL <image>
kubectl get pod <name> -n prod -o jsonpath='{.metadata.ownerReferences[*].kind}'
kubectl delete deployment <name> -n prod # or: delete pod, if it is a bare Pod
Deleting the Pod of a Deployment is the classic mistake: it comes straight back.
Task 15
Policy with omitStages: ["RequestReceived"], a RequestResponse rule scoped toconfig-data for secrets/configmaps, then Metadata catch-all; static pod mounts
for both the policy file (type: File) and the log directory
(type: DirectoryOrCreate, mounted read-write); --audit-log-path,--audit-log-maxage=30. Verify with a kubectl create secret and jq on the last
line of the log.
Task 16
Whole rule, same name, in /etc/falco/falco_rules.local.yaml, output including%container.id; file_output enabled at /var/log/falco/events.log,stdout_output: false; systemctl restart falco; trigger with a write to /etc.
Task 17
kubectl exec -n prod suspect -- ps aux --sort=-%cpu | head
kubectl exec -n prod suspect -- ls -l /proc/1/exe
sudo crictl ps | grep suspect
Write the in-container path of the miner to /root/suspect.txt. A `strace -f -e
trace=execve` on the node against the container PID shows the same answer with the
arguments.