Mock exams · Mock paper B — mixed and timed
Answers — Mock paper B — mixed and timed
One answer per task, numbered like the paper. Commands assume a RHEL 10 system; check the result before you move on.
Task 1
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to: [{ipBlock: {cidr: 10.0.0.0/8, except: ["10.0.5.0/24"]}}]
- to: [{namespaceSelector: {}}]
ports: [{protocol: UDP, port: 53}, {protocol: TCP, port: 53}]
Note the two separate to items: an ipBlock cannot live in the same item as anamespaceSelector.
Task 2
# /var/lib/kubelet/config.yaml
authentication:
anonymous: {enabled: false}
webhook: {enabled: true}
authorization: {mode: Webhook}
readOnlyPort: 0
sudo systemctl daemon-reload && sudo systemctl restart kubelet
ss -tulpn | grep 10255 # nothing
kubectl get nodes # still Ready
Task 3
- --tls-min-version=VersionTLS12
Verify withopenssl s_client -connect 127.0.0.1:6443 -tls1 </dev/null → handshake failure,
and the same with -tls1_2 → success. Removing --tls-max-version also matters
if the cluster had pinned TLS 1.3 only.
Task 4
apiVersion: v1
kind: ServiceAccount
metadata: {name: report, namespace: prod}
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: {name: report, namespace: prod}
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: {name: report, namespace: prod}
subjects: [{kind: ServiceAccount, name: report}]
roleRef: {kind: Role, name: report, apiGroup: rbac.authorization.k8s.io}
Verify with kubectl auth can-i --list --as=system:serviceaccount:prod:report.
Task 5
kubectl get clusterrole wide -o yaml > /tmp/wide.yaml
# replace rules with: apiGroups [""], resources ["configmaps"], verbs ["get"]
kubectl apply -f /tmp/wide.yaml
kubectl auth can-i get secrets --as=system:serviceaccount:prod:app # must be no
kubectl auth can-i get configmaps --as=system:serviceaccount:prod:app
The trap: if a workload actually reads Secrets, "reduce" means reduce to what it
uses — check the Pods in prod before deleting the whole rule.
Task 6
securityContext:
seccompProfile: {type: RuntimeDefault}
Pod-level is enough for every container. Verifykubectl get pod -n prod -l app=api -o jsonpath='{..seccompProfile.type}'.
Task 7
readOnlyRootFilesystem: true plus two emptyDir volumes mounted at/var/cache/app and /tmp. Verify Running and that a write outside those paths
fails.
Task 8
kubectl label ns ml \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/audit=restricted --overwrite
A hostNetwork: true Pod is admitted (baseline allows it in this scenario's
version of the standard) and kubectl prints `Warning: would violate PodSecurity
"restricted"`. If the Pod is rejected instead, the enforce level is wrong.
Task 9
ConstraintTemplate k8sallowedrepos with startswith(container.image, repo),
Constraint with parameters.repos: ["registry.example.com/"] andmatch.kinds: [{apiGroups: [""], kinds: ["Pod"]}], scoped bymatch.namespaces: ["prod"]. Verify with a kubectl run using nginx:1.27 —
it must be rejected with comes from an untrusted registry.
Task 10
volumeMounts:
- {name: db, mountPath: /etc/db, readOnly: true}
volumes:
- name: db
secret:
secretName: db
defaultMode: 0400
Remove the env.valueFrom.secretKeyRef entries. Verify the files exist with mode-r-------- and that no Secret value appears in kubectl exec -- env.
Task 11
spec:
runtimeClassName: gvisor
Verify kubectl get pod isolated -n prod -o jsonpath='{.spec.runtimeClassName}'
and, on the node, crictl inspect <id> | grep -i runtimeType.
Task 12
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata: {name: default, namespace: prod}
spec:
mtls: {mode: STRICT}
Verify kubectl get peerauthentication -n prod -o yaml and that every Pod has2/2 containers.
Task 13
gcr.io/distroless/nodejs22-debian12@sha256:<digest>, or the smallest image that
still carries the runtime the app needs. "Pinned by digest" is checked literally:
the image: string must contain @sha256:.
Task 14
bom generate --image registry.example.com/app:1.4.2 -o /tmp/sbom.spdx
bom document query /tmp/sbom.spdx 'name:openssl'
echo yes > /root/sbom-answer.txt # or: no
bom document outline also works; the answer is the presence of the package, not
the format.
Task 15
sudo grep '"verb":"delete"' /var/log/kubernetes/audit.log \
| jq -r 'select(.objectRef.resource=="secrets") | .user.username' | sort -u > /root/deleters.txt
cat /root/deleters.txt
If the log is not JSON-per-line on the node, jq -c each line separately. Watch
for system:serviceaccount:... users — those are the interesting ones.
Task 16
# /etc/falco/falco_rules.local.yaml
- rule: Terminal shell in container
desc: a shell was spawned in a container with an attached terminal
condition: >
spawned_process and container and shell_procs and proc.tty != 0
and container_entrypoint and k8s.ns.name = "prod"
output: "Shell in container (pod=%k8s.pod.name ns=%k8s.ns.name image=%container.image.repository)"
priority: NOTICE
tags: [container, shell]
Keep the whole rule and change only condition and output;systemctl restart falco; trigger with kubectl exec -it -n prod <pod> -- bash
and tail /var/log/falco/events.log.
Task 17
kubectl get pods -A -o json | jq -r '
.items[]
| select(.spec.hostNetwork==true or .spec.hostPID==true
or any(.spec.containers[]; .securityContext.privileged==true)
or any(.spec.containers[]; (.securityContext.runAsNonRoot//false)==false))
| "\(.metadata.namespace)/\(.metadata.name)"' | sort -u > /root/insecure-pods.txt
Read the task literally: privileged, hostNetwork, or root — not "missing
readOnlyRootFilesystem".