Linux Foundation Certified Kubernetes Security Specialist (CKS) - CKS Exam Practice Test
Question 1
SIMULATION
Service is running on port 389 inside the system, find the process-id of the process, and stores the names of all the open-files inside the /candidate/KH77539/files.txt, and also delete the binary.
Service is running on port 389 inside the system, find the process-id of the process, and stores the names of all the open-files inside the /candidate/KH77539/files.txt, and also delete the binary.
Correct Answer:
See the Explanation belowExplanation:
root# netstat -ltnup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:17600 0.0.0.0:* LISTEN 1293/dropbox tcp 0 0 127.0.0.1:17603 0.0.0.0:* LISTEN 1293/dropbox tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 575/sshd tcp 0 0 127.0.0.1:9393 0.0.0.0:* LISTEN 900/perl tcp 0 0 :::80 :::* LISTEN 9583/docker-proxy tcp 0 0 :::443 :::* LISTEN 9571/docker-proxy udp 0 0 0.0.0.0:68 0.0.0.0:* 8822/dhcpcd
...
root# netstat -ltnup | grep ':22'
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 575/sshd
The ss command is the replacement of the netstat command.
Now let's see how to use the ss command to see which process is listening on port 22:
root# ss -ltnup 'sport = :22'
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:("sshd",pid=575,fd=3))
root# netstat -ltnup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:17600 0.0.0.0:* LISTEN 1293/dropbox tcp 0 0 127.0.0.1:17603 0.0.0.0:* LISTEN 1293/dropbox tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 575/sshd tcp 0 0 127.0.0.1:9393 0.0.0.0:* LISTEN 900/perl tcp 0 0 :::80 :::* LISTEN 9583/docker-proxy tcp 0 0 :::443 :::* LISTEN 9571/docker-proxy udp 0 0 0.0.0.0:68 0.0.0.0:* 8822/dhcpcd
...
root# netstat -ltnup | grep ':22'
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 575/sshd
The ss command is the replacement of the netstat command.
Now let's see how to use the ss command to see which process is listening on port 22:
root# ss -ltnup 'sport = :22'
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:("sshd",pid=575,fd=3))
Question 2
SIMULATION
Context
For testing purposes, the kubeadm provisioned cluster 's API server
was configured to allow unauthenticated and unauthorized access.
Task
First, secure the cluster 's API server configuring it as follows:
. Forbid anonymous authentication
. Use authorization mode Node,RBAC
. Use admission controller NodeRestriction
The cluster uses the Docker Engine as its container runtime . If needed, use the docker command to troubleshoot running containers.
kubectl is configured to use unauthenticated and unauthorized access. You do not have to change it, but be aware that kubectl will stop working once you have secured the cluster .
You can use the cluster 's original kubectl configuration file located at etc/kubernetes/admin.conf to access the secured cluster.
Next, to clean up, remove the ClusterRoleBinding
system:anonymous.
Context
For testing purposes, the kubeadm provisioned cluster 's API server
was configured to allow unauthenticated and unauthorized access.
Task
First, secure the cluster 's API server configuring it as follows:
. Forbid anonymous authentication
. Use authorization mode Node,RBAC
. Use admission controller NodeRestriction
The cluster uses the Docker Engine as its container runtime . If needed, use the docker command to troubleshoot running containers.
kubectl is configured to use unauthenticated and unauthorized access. You do not have to change it, but be aware that kubectl will stop working once you have secured the cluster .
You can use the cluster 's original kubectl configuration file located at etc/kubernetes/admin.conf to access the secured cluster.
Next, to clean up, remove the ClusterRoleBinding
system:anonymous.
Correct Answer:
See the Explanation below for complete solution
Explanation:
1) SSH to control-plane node
ssh cks000002
sudo -i
2) Edit API Server static pod manifest
API server in kubeadm runs as a static pod.
vi /etc/kubernetes/manifests/kube-apiserver.yaml
3) Apply required API Server security settings
3.1 Forbid anonymous authentication
Find command: section and ensure this line exists:
- --anonymous-auth=false
3.2 Use authorization mode Node,RBAC
Ensure exactly this line exists (and no AlwaysAllow):
- --authorization-mode=Node,RBAC
❌ Remove if present:
- --authorization-mode=AlwaysAllow
3.3 Enable admission controller NodeRestriction
Find --enable-admission-plugins and ensure NodeRestriction is included.
Correct example:
- --enable-admission-plugins=NodeRestriction
If other plugins already exist, append NodeRestriction, e.g.:
- --enable-admission-plugins=NamespaceLifecycle,ServiceAccount,NodeRestriction
4) Save file and let kubelet restart API server
Just save and exit (:wq)
Kubelet will automatically restart the API server pod.
5) Switch kubectl to secured config
Current kubectl will stop working after API server hardening.
export KUBECONFIG=/etc/kubernetes/admin.conf
Verify access:
kubectl get nodes
6) Remove insecure ClusterRoleBinding
Delete system:anonymous binding:
kubectl delete clusterrolebinding system:anonymous
Verify removal:
kubectl get clusterrolebinding | grep anonymous
(no output = correct)
7) Quick validation (optional but fast)
API server flags check:
grep -n "anonymous-auth" /etc/kubernetes/manifests/kube-apiserver.yaml
grep -n "authorization-mode" /etc/kubernetes/manifests/kube-apiserver.yaml grep -n "NodeRestriction" /etc/kubernetes/manifests/kube-apiserver.yaml
Explanation:
1) SSH to control-plane node
ssh cks000002
sudo -i
2) Edit API Server static pod manifest
API server in kubeadm runs as a static pod.
vi /etc/kubernetes/manifests/kube-apiserver.yaml
3) Apply required API Server security settings
3.1 Forbid anonymous authentication
Find command: section and ensure this line exists:
- --anonymous-auth=false
3.2 Use authorization mode Node,RBAC
Ensure exactly this line exists (and no AlwaysAllow):
- --authorization-mode=Node,RBAC
❌ Remove if present:
- --authorization-mode=AlwaysAllow
3.3 Enable admission controller NodeRestriction
Find --enable-admission-plugins and ensure NodeRestriction is included.
Correct example:
- --enable-admission-plugins=NodeRestriction
If other plugins already exist, append NodeRestriction, e.g.:
- --enable-admission-plugins=NamespaceLifecycle,ServiceAccount,NodeRestriction
4) Save file and let kubelet restart API server
Just save and exit (:wq)
Kubelet will automatically restart the API server pod.
5) Switch kubectl to secured config
Current kubectl will stop working after API server hardening.
export KUBECONFIG=/etc/kubernetes/admin.conf
Verify access:
kubectl get nodes
6) Remove insecure ClusterRoleBinding
Delete system:anonymous binding:
kubectl delete clusterrolebinding system:anonymous
Verify removal:
kubectl get clusterrolebinding | grep anonymous
(no output = correct)
7) Quick validation (optional but fast)
API server flags check:
grep -n "anonymous-auth" /etc/kubernetes/manifests/kube-apiserver.yaml
grep -n "authorization-mode" /etc/kubernetes/manifests/kube-apiserver.yaml grep -n "NodeRestriction" /etc/kubernetes/manifests/kube-apiserver.yaml
Question 3
SIMULATION
Create a new ServiceAccount named backend-sa in the existing namespace default, which has the capability to list the pods inside the namespace default.
Create a new Pod named backend-pod in the namespace default, mount the newly created sa backend-sa to the pod, and Verify that the pod is able to list pods.
Ensure that the Pod is running.
Create a new ServiceAccount named backend-sa in the existing namespace default, which has the capability to list the pods inside the namespace default.
Create a new Pod named backend-pod in the namespace default, mount the newly created sa backend-sa to the pod, and Verify that the pod is able to list pods.
Ensure that the Pod is running.
Correct Answer:
A service account provides an identity for processes that run in a Pod.
When you (a human) access the cluster (for example, using kubectl), you are authenticated by the apiserver as a particular User Account (currently this is usually admin, unless your cluster administrator has customized your cluster). Processes in containers inside pods can also contact the apiserver. When they do, they are authenticated as a particular Service Account (for example, default).
When you create a pod, if you do not specify a service account, it is automatically assigned the default service account in the same namespace. If you get the raw json or yaml for a pod you have created (for example, kubectl get pods/<podname> -o yaml), you can see the spec.serviceAccountName field has been automatically set.
You can access the API from inside a pod using automatically mounted service account credentials, as described in Accessing the Cluster. The API permissions of the service account depend on the authorization plugin and policy in use.
In version 1.6+, you can opt out of automounting API credentials for a service account by setting automountServiceAccountToken: false on the service account:
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
In version 1.6+, you can also opt out of automounting API credentials for a particular pod:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
The pod spec takes precedence over the service account if both specify a automountServiceAccountToken value.
When you (a human) access the cluster (for example, using kubectl), you are authenticated by the apiserver as a particular User Account (currently this is usually admin, unless your cluster administrator has customized your cluster). Processes in containers inside pods can also contact the apiserver. When they do, they are authenticated as a particular Service Account (for example, default).
When you create a pod, if you do not specify a service account, it is automatically assigned the default service account in the same namespace. If you get the raw json or yaml for a pod you have created (for example, kubectl get pods/<podname> -o yaml), you can see the spec.serviceAccountName field has been automatically set.
You can access the API from inside a pod using automatically mounted service account credentials, as described in Accessing the Cluster. The API permissions of the service account depend on the authorization plugin and policy in use.
In version 1.6+, you can opt out of automounting API credentials for a service account by setting automountServiceAccountToken: false on the service account:
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
In version 1.6+, you can also opt out of automounting API credentials for a particular pod:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
The pod spec takes precedence over the service account if both specify a automountServiceAccountToken value.
Question 4
SIMULATION
Documentation
Deployment, Pod Security Admission, Pod Security Standards
You must connect to the correct host . Failure to do so may result in a zero score.
[candidate@base] $ ssh cks000036
Context
For compliance, all user namespaces enforce the restricted Pod Security Standard .
Task
The confidential namespace contains a Deployment that is not compliant with the restricted Pod Security Standard . Thus, its Pods can not be scheduled.
Modify the Deployment to be compliant and verify that the Pods are running.
The Deployment's manifest file can be found at /home/candidate/nginx-unprivileged.yaml.
Documentation
Deployment, Pod Security Admission, Pod Security Standards
You must connect to the correct host . Failure to do so may result in a zero score.
[candidate@base] $ ssh cks000036
Context
For compliance, all user namespaces enforce the restricted Pod Security Standard .
Task
The confidential namespace contains a Deployment that is not compliant with the restricted Pod Security Standard . Thus, its Pods can not be scheduled.
Modify the Deployment to be compliant and verify that the Pods are running.
The Deployment's manifest file can be found at /home/candidate/nginx-unprivileged.yaml.
Correct Answer:
See the Explanation below for complete solution
Explanation:
1) Connect to the correct host
ssh cks000036
sudo -i
export KUBECONFIG=/etc/kubernetes/admin.conf
2) Confirm the failing Pods + see the PSA error (fast)
kubectl -n confidential get deploy
kubectl -n confidential get pods
kubectl -n confidential describe deploy <deployment-name> | sed -n '/Events/,$p' (You'll usually see "violates PodSecurity 'restricted' ..." with the exact missing fields.)
3) Edit the provided manifest
vi /home/candidate/nginx-unprivileged.yaml
You must ensure the Pod template becomes compliant. Add/ensure the following exact blocks:
4) Add Pod-level securityContext (under spec.template.spec)
Find:
spec:
template:
spec:
Add this block under it (or merge if securityContext: already exists):
securityContext:
runAsNonRoot: true
runAsUser: 65535
seccompProfile:
type: RuntimeDefault
5) Add Container-level securityContext (under the nginx container)
Find:
containers:
- name: ...
image: ...
Under that container, add (or adjust) this exact block:
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
If there are multiple containers, apply the same container securityContext to each one.
Save and exit:
:wq
6) Apply the manifest to the confidential namespace
kubectl -n confidential apply -f /home/candidate/nginx-unprivileged.yaml Wait rollout:
kubectl -n confidential rollout status deployment/<deployment-name>
If you don't know the deployment name from the file, list:
kubectl -n confidential get deploy
7) Verify Pods are running
kubectl -n confidential get pods -o wide
If still failing, show the exact PSA violation (this tells you what else to fix):
kubectl -n confidential describe pod <pod-name> | sed -n '/Events/,$p'
Quick "if it still fails" fixes (common restricted blockers)
Open the manifest again and ensure these are NOT set (or are removed/false):
hostNetwork: true
hostPID: true
hostIPC: true
any hostPort:
privileged: true
capabilities.add:
seccompProfile: Unconfined
runAsUser: 0 or runAsNonRoot: false
Then re-apply.
Minimal compliant result (what the grader expects)
Your Pod template should include:
seccompProfile: RuntimeDefault
runAsNonRoot: true (and a non-root UID like 65535)
container: allowPrivilegeEscalation: false
container: capabilities.drop: [ALL]
container: readOnlyRootFilesystem: true
Explanation:
1) Connect to the correct host
ssh cks000036
sudo -i
export KUBECONFIG=/etc/kubernetes/admin.conf
2) Confirm the failing Pods + see the PSA error (fast)
kubectl -n confidential get deploy
kubectl -n confidential get pods
kubectl -n confidential describe deploy <deployment-name> | sed -n '/Events/,$p' (You'll usually see "violates PodSecurity 'restricted' ..." with the exact missing fields.)
3) Edit the provided manifest
vi /home/candidate/nginx-unprivileged.yaml
You must ensure the Pod template becomes compliant. Add/ensure the following exact blocks:
4) Add Pod-level securityContext (under spec.template.spec)
Find:
spec:
template:
spec:
Add this block under it (or merge if securityContext: already exists):
securityContext:
runAsNonRoot: true
runAsUser: 65535
seccompProfile:
type: RuntimeDefault
5) Add Container-level securityContext (under the nginx container)
Find:
containers:
- name: ...
image: ...
Under that container, add (or adjust) this exact block:
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
If there are multiple containers, apply the same container securityContext to each one.
Save and exit:
:wq
6) Apply the manifest to the confidential namespace
kubectl -n confidential apply -f /home/candidate/nginx-unprivileged.yaml Wait rollout:
kubectl -n confidential rollout status deployment/<deployment-name>
If you don't know the deployment name from the file, list:
kubectl -n confidential get deploy
7) Verify Pods are running
kubectl -n confidential get pods -o wide
If still failing, show the exact PSA violation (this tells you what else to fix):
kubectl -n confidential describe pod <pod-name> | sed -n '/Events/,$p'
Quick "if it still fails" fixes (common restricted blockers)
Open the manifest again and ensure these are NOT set (or are removed/false):
hostNetwork: true
hostPID: true
hostIPC: true
any hostPort:
privileged: true
capabilities.add:
seccompProfile: Unconfined
runAsUser: 0 or runAsNonRoot: false
Then re-apply.
Minimal compliant result (what the grader expects)
Your Pod template should include:
seccompProfile: RuntimeDefault
runAsNonRoot: true (and a non-root UID like 65535)
container: allowPrivilegeEscalation: false
container: capabilities.drop: [ALL]
container: readOnlyRootFilesystem: true
Question 5
SIMULATION
Enable audit logs in the cluster, To Do so, enable the log backend, and ensure that
1. logs are stored at /var/log/kubernetes-logs.txt.
2. Log files are retained for 12 days.
3. at maximum, a number of 8 old audit logs files are retained.
4. set the maximum size before getting rotated to 200MB
Edit and extend the basic policy to log:
1. namespaces changes at RequestResponse
2. Log the request body of secrets changes in the namespace kube-system.
3. Log all other resources in core and extensions at the Request level.
4. Log "pods/portforward", "services/proxy" at Metadata level.
5. Omit the Stage RequestReceived All other requests at the Metadata level
Enable audit logs in the cluster, To Do so, enable the log backend, and ensure that
1. logs are stored at /var/log/kubernetes-logs.txt.
2. Log files are retained for 12 days.
3. at maximum, a number of 8 old audit logs files are retained.
4. set the maximum size before getting rotated to 200MB
Edit and extend the basic policy to log:
1. namespaces changes at RequestResponse
2. Log the request body of secrets changes in the namespace kube-system.
3. Log all other resources in core and extensions at the Request level.
4. Log "pods/portforward", "services/proxy" at Metadata level.
5. Omit the Stage RequestReceived All other requests at the Metadata level
Correct Answer:
Kubernetes auditing provides a security-relevant chronological set of records about a cluster. Kube-apiserver performs auditing. Each request on each stage of its execution generates an event, which is then pre-processed according to a certain policy and written to a backend. The policy determines what's recorded and the backends persist the records.
You might want to configure the audit log as part of compliance with the CIS (Center for Internet Security) Kubernetes Benchmark controls.
The audit log can be enabled by default using the following configuration in cluster.yml:
services:
kube-api:
audit_log:
enabled: true
When the audit log is enabled, you should be able to see the default values at /etc/kubernetes/audit-policy.yaml The log backend writes audit events to a file in JSONlines format. You can configure the log audit backend using the following kube-apiserver flags:
--audit-log-path specifies the log file path that log backend uses to write audit events. Not specifying this flag disables log backend. - means standard out
--audit-log-maxage defined the maximum number of days to retain old audit log files
--audit-log-maxbackup defines the maximum number of audit log files to retain
--audit-log-maxsize defines the maximum size in megabytes of the audit log file before it gets rotated If your cluster's control plane runs the kube-apiserver as a Pod, remember to mount the hostPath to the location of the policy file and log file, so that audit records are persisted. For example:
--audit-policy-file=/etc/kubernetes/audit-policy.yaml \
--audit-log-path=/var/log/audit.log
You might want to configure the audit log as part of compliance with the CIS (Center for Internet Security) Kubernetes Benchmark controls.
The audit log can be enabled by default using the following configuration in cluster.yml:
services:
kube-api:
audit_log:
enabled: true
When the audit log is enabled, you should be able to see the default values at /etc/kubernetes/audit-policy.yaml The log backend writes audit events to a file in JSONlines format. You can configure the log audit backend using the following kube-apiserver flags:
--audit-log-path specifies the log file path that log backend uses to write audit events. Not specifying this flag disables log backend. - means standard out
--audit-log-maxage defined the maximum number of days to retain old audit log files
--audit-log-maxbackup defines the maximum number of audit log files to retain
--audit-log-maxsize defines the maximum size in megabytes of the audit log file before it gets rotated If your cluster's control plane runs the kube-apiserver as a Pod, remember to mount the hostPath to the location of the policy file and log file, so that audit records are persisted. For example:
--audit-policy-file=/etc/kubernetes/audit-policy.yaml \
--audit-log-path=/var/log/audit.log
Question 6
SIMULATION
You must connect to the correct host . Failure to do so may
result in a zero score.
[candidato@base] $ ssh cks000023
Task
Analyze and edit the Dockerfile located at /home/candidate/subtle-bee/build/Dockerfile, fixing one instruction present in the file that is a prominent security/best-practice issue.
Do not add or remove instructions; only modify the one existing instruction with a security/best-practice concern.
Do not build the Dockerfile, Failure to do so may result in running out of storage and a zero score.
Analyze and edit the given manifest file /home/candidate/subtle-bee/deployment.yaml, fixing one fields present in the file that are a prominent security/best-practice issue.
Do not add or remove fields; only modify the one existing field with a security/best-practice concern.
Should you need an unprivileged user for any of the tasks, use user nobody with user ID 65535.
You must connect to the correct host . Failure to do so may
result in a zero score.
[candidato@base] $ ssh cks000023
Task
Analyze and edit the Dockerfile located at /home/candidate/subtle-bee/build/Dockerfile, fixing one instruction present in the file that is a prominent security/best-practice issue.
Do not add or remove instructions; only modify the one existing instruction with a security/best-practice concern.
Do not build the Dockerfile, Failure to do so may result in running out of storage and a zero score.
Analyze and edit the given manifest file /home/candidate/subtle-bee/deployment.yaml, fixing one fields present in the file that are a prominent security/best-practice issue.
Do not add or remove fields; only modify the one existing field with a security/best-practice concern.
Should you need an unprivileged user for any of the tasks, use user nobody with user ID 65535.
Correct Answer:
See the Explanation below for complete solution
Explanation:
0) Connect to the correct host
ssh cks000023
sudo -i
PART A - Fix ONE prominent Dockerfile security/best-practice issue
1) Open the Dockerfile
vi /home/candidate/subtle-bee/build/Dockerfile
2) Find the "most obvious" security/best-practice problem and modify ONLY THAT ONE instruction Use / search in vi to quickly find candidates:
Candidate 1 (very common): USER root (or no USER but a USER 0)
Search:
/USER
If you see:
USER root
Change that single instruction to:
USER 65535
(or USER nobody if that exact word is already used in the file-but the task explicitly allows UID 65535, so USER 65535 is safest.)
✅ This is one-instruction change and is a top-tier best practice.
Candidate 2 (very common): FROM <image>:latest
Search:
/FROM
If you see something like:
FROM nginx:latest
Change ONLY that line to a pinned tag (example):
FROM nginx:1.25.5
(Any non-latest pinned version is the point. Don't add a digest line; just modify the existing FROM line.) Candidate 3: ADD http://... (remote URL download) Search:
/ADD
If you see remote URL usage like:
ADD https://example.com/app.tar.gz /app/
Change that single instruction to COPY only if it's copying local files.
If it's a remote URL, the more "correct" fix would normally be using curl with verification, but that would require adding instructions (not allowed).
So in this exam constraint, do NOT pick this unless it's actually a local add like:
ADD . /app
Then change just the word:
COPY . /app
3) Save and exit
:wq
Don't run docker build (task forbids building).
PART B - Fix ONE prominent security/best-practice issue in the Deployment manifest
4) Open the manifest
vi /home/candidate/subtle-bee/deployment.yaml
5) Change ONLY ONE existing field that is a clear security issue
Use / search in vi for the usual "bad fields":
Option 1 (most common): running as root
Search:
/runAsUser
If you see:
runAsUser: 0
Change that one existing field value to:
runAsUser: 65535
✅ This is a single-field change and matches the prompt hint.
Option 2: privileged container
Search:
/privileged
If you see:
privileged: true
Change only that value to:
privileged: false
Option 3: allow privilege escalation
Search:
/allowPrivilegeEscalation
If you see:
allowPrivilegeEscalation: true
Change only that value to:
allowPrivilegeEscalation: false
Option 4: writable root filesystem
Search:
/readOnlyRootFilesystem
If you see:
readOnlyRootFilesystem: false
Change only that value to:
readOnlyRootFilesystem: true
Option 5: image uses :latest
Search:
/image:
If you see:
image: something:latest
Change only that value to a pinned tag, e.g.:
image: something:1.2.3
6) Save and exit
:wq
What to pick (fast decision rule)
If you see run as root in either file, that's usually the highest scoring / most "prominent" security issue.
Dockerfile: USER root → USER 65535
Deployment: runAsUser: 0 → runAsUser: 65535
Those are perfect because you only modify one line/field and it matches the hint.
Explanation:
0) Connect to the correct host
ssh cks000023
sudo -i
PART A - Fix ONE prominent Dockerfile security/best-practice issue
1) Open the Dockerfile
vi /home/candidate/subtle-bee/build/Dockerfile
2) Find the "most obvious" security/best-practice problem and modify ONLY THAT ONE instruction Use / search in vi to quickly find candidates:
Candidate 1 (very common): USER root (or no USER but a USER 0)
Search:
/USER
If you see:
USER root
Change that single instruction to:
USER 65535
(or USER nobody if that exact word is already used in the file-but the task explicitly allows UID 65535, so USER 65535 is safest.)
✅ This is one-instruction change and is a top-tier best practice.
Candidate 2 (very common): FROM <image>:latest
Search:
/FROM
If you see something like:
FROM nginx:latest
Change ONLY that line to a pinned tag (example):
FROM nginx:1.25.5
(Any non-latest pinned version is the point. Don't add a digest line; just modify the existing FROM line.) Candidate 3: ADD http://... (remote URL download) Search:
/ADD
If you see remote URL usage like:
ADD https://example.com/app.tar.gz /app/
Change that single instruction to COPY only if it's copying local files.
If it's a remote URL, the more "correct" fix would normally be using curl with verification, but that would require adding instructions (not allowed).
So in this exam constraint, do NOT pick this unless it's actually a local add like:
ADD . /app
Then change just the word:
COPY . /app
3) Save and exit
:wq
Don't run docker build (task forbids building).
PART B - Fix ONE prominent security/best-practice issue in the Deployment manifest
4) Open the manifest
vi /home/candidate/subtle-bee/deployment.yaml
5) Change ONLY ONE existing field that is a clear security issue
Use / search in vi for the usual "bad fields":
Option 1 (most common): running as root
Search:
/runAsUser
If you see:
runAsUser: 0
Change that one existing field value to:
runAsUser: 65535
✅ This is a single-field change and matches the prompt hint.
Option 2: privileged container
Search:
/privileged
If you see:
privileged: true
Change only that value to:
privileged: false
Option 3: allow privilege escalation
Search:
/allowPrivilegeEscalation
If you see:
allowPrivilegeEscalation: true
Change only that value to:
allowPrivilegeEscalation: false
Option 4: writable root filesystem
Search:
/readOnlyRootFilesystem
If you see:
readOnlyRootFilesystem: false
Change only that value to:
readOnlyRootFilesystem: true
Option 5: image uses :latest
Search:
/image:
If you see:
image: something:latest
Change only that value to a pinned tag, e.g.:
image: something:1.2.3
6) Save and exit
:wq
What to pick (fast decision rule)
If you see run as root in either file, that's usually the highest scoring / most "prominent" security issue.
Dockerfile: USER root → USER 65535
Deployment: runAsUser: 0 → runAsUser: 65535
Those are perfect because you only modify one line/field and it matches the hint.
Question 7
SIMULATION
Create a new NetworkPolicy named deny-all in the namespace testing which denies all traffic of type ingress and egress traffic
Create a new NetworkPolicy named deny-all in the namespace testing which denies all traffic of type ingress and egress traffic
Correct Answer:
You can create a "default" isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any ingress traffic to those pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
You can create a "default" egress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any egress traffic from those pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
Default deny all ingress and all egress traffic
You can create a "default" policy for a namespace which prevents all ingress AND egress traffic by creating the following NetworkPolicy in that namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
This ensures that even pods that aren't selected by any other NetworkPolicy will not be allowed ingress or egress traffic.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
You can create a "default" egress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any egress traffic from those pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
Default deny all ingress and all egress traffic
You can create a "default" policy for a namespace which prevents all ingress AND egress traffic by creating the following NetworkPolicy in that namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
This ensures that even pods that aren't selected by any other NetworkPolicy will not be allowed ingress or egress traffic.

