I have an exiting Deployment in a Kubernetes cluster with the following sepecifications:
- Deployment name => nginx-deployment
- Image => nginx:1.14.2
- Replicas => 3
The tasks is to Modify Deployment frontend-deploy as follows:
• Start the container with a user ID of 1000
• Do not allow processes to gain privileges beyond those of their parents (disable allowPrivilegeEscalation).
• Load the container’s root filesystem as read-only (read-only permissions to the root file).
NOTE:
I have used the following YAML declaration file, but I keep getting errors
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
containers:
- image: nginx:1.14.2
name: nginx
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources: {}
status: {}
First, I literally cannot tell from your YAML – indentation is key here, and you’ve pasted your YAML in without putting it into
A code window
That preserves the correct
indentation.
Use the </>
button to create the right markup (it’s based on Markdown) so I can tell whether your securityContext is like this:
containers:
- image: nginx:1.14.2
name: nginx
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources: {}
which would at least potentially be correct.
Task: Modify Deployment nginx-deployment the sec-ns namespace as follows
• Start the container with a user ID of 1000
• Do not allow processes to gain privileges beyond those of their parents (disable allowPrivilegeEscalation).
• Load the container’s root filesystem as read-only (read-only permissions to the root file).
.
- This is the code block I made use of. I placed the security context under the container section.
- The ( namespace: sec-ns ) and user with ID: 1000 already exist. However, I still keep getting errors.
- Can you please check if there is anything I am missing out?
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
name: nginx-deployment
namespace: sec-ns
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
containers:
- image: nginx:1.14.2
name: nginx
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources: {}
status: {}
Moreover, I also tried placing the SecurityContext under the specs sections just to see if it would work, but in both cases, it still didn’t work.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: sec-ns
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
The allowed fields under securityContext
change depending upon whether you’re in a container or directly under spec, so I"m not surprised the second example didn’t load.
When you say the first example “didn’t work” what do you mean? You mean that that the grader did not verify it? Or that there was some error printed somehow?
You might want to look at the log of the nginx container, BTW. If you set the root filesystem to read only, if something needs to write something, there will be trouble. You might need to create a temporary, writeable directory so that the container runs correctly.
So, when the Security Context was placed within the container:
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
name: nginx-deployment
namespace: sec-ns
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
containers:
- image: nginx:1.14.2
name: nginx
securityContext:
runAsUser: 1001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources: {}
status: {}
The deployment object was created, and the associated pods where also created. However, the STATUS of the pods were in a CrashLoopBackOff state.
controlplane ~ ➜ k -n sec-ns get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-7d46769d7c-ww2ww 0/1 CrashLoopBackOff 3 (31s ago) 76s
nginx-deployment-7d46769d7c-b5p9b 0/1 CrashLoopBackOff 3 (24s ago) 76s
nginx-deployment-7d46769d7c-5zwnx 0/1 CrashLoopBackOff 3 (26s ago) 76s
And when I described the events in one of the pods:
controlplane ~ ➜ k -n sec-ns describe pods nginx-deployment-7d46769d7c-ww2ww
Name: nginx-deployment-7d46769d7c-ww2ww
Namespace: sec-ns
Priority: 0
Service Account: default
Node: controlplane/192.5.2.6
Start Time: Fri, 03 May 2024 03:19:15 +0000
Labels: app=nginx-deployment
pod-template-hash=7d46769d7c
Annotations: <none>
Status: Running
IP: 10.42.0.9
IPs:
IP: 10.42.0.9
Controlled By: ReplicaSet/nginx-deployment-7d46769d7c
Containers:
nginx:
Container ID: containerd://c9dd166d427528c900a8a7c11578ad11d322b3ed5e095ee59716301e968515ef
Image: nginx:1.14.2
Image ID: docker.io/library/nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
Port: <none>
Host Port: <none>
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Started: Fri, 03 May 2024 03:25:02 +0000
Finished: Fri, 03 May 2024 03:25:02 +0000
Ready: False
Restart Count: 6
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-rvz9k (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-rvz9k:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m48s default-scheduler Successfully assigned sec-ns/nginx-deployment-7d46769d7c-ww2ww to controlplane
Normal Pulling 6m48s kubelet Pulling image "nginx:1.14.2"
Normal Pulled 6m44s kubelet Successfully pulled image "nginx:1.14.2" in 3.626s (3.626s including waiting)
Normal Pulled 5m21s (x4 over 6m43s) kubelet Container image "nginx:1.14.2" already present on machine
Normal Created 5m21s (x5 over 6m44s) kubelet Created container nginx
Normal Started 5m21s (x5 over 6m44s) kubelet Started container nginx
Warning BackOff 100s (x26 over 6m41s) kubelet Back-off restarting failed container nginx in pod nginx-deployment-7d46769d7c-ww2ww_sec-ns(0b57761f-d1d6-4b8f-8521-33504045ef53)
The logs of one of the pods:
controlplane ~ ➜ k -n sec-ns logs nginx-deployment-7d46769d7c-ww2ww
2024/05/03 03:25:02 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2024/05/03 03:25:02 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)
The warnings you can ignore. Looks like the process cannot write to /var/cache/nginx. You’ll need to make that write possible by using emptyDir or some similar trick, it would appear.
As suggested, I decided to try an emptyDir volume approach using the following code:
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
name: nginx-deployment
namespace: sec-ns
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
containers:
- image: nginx:1.14.2
name: nginx
securityContext:
runAsUser: 1001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
volumeMounts:
- name: readonly-volume
mountPath: /var/cache/nginx
readOnly: true
volumes:
- name: readonly-volume
emptyDir: {}
However, I still keep getting this errors from the logs:
controlplane ~ ➜ k -n sec-ns get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-c6fffd664-nrlq4 0/1 Error 2 (25s ago) 28s
nginx-deployment-c6fffd664-zfqvn 0/1 Error 2 (26s ago) 28s
nginx-deployment-c6fffd664-5l45n 0/1 Error 2 (25s ago) 28s
controlplane ~ ➜ k -n sec-ns logs nginx-deployment-c6fffd664-nrlq4
2024/05/03 03:54:30 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2024/05/03 03:54:30 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)
You’re close; you don’t want that cache volume to be readOnly – nginx needs to write to it.
I am using this code block and everything seems to be working okay…
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
name: nginx-deployment
namespace: sec-ns
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
containers:
- image: nginx:1.14.2
name: nginx
securityContext:
runAsUser: 1001
allowPrivilegeEscalation: false
volumeMounts:
- name: readonly-volume
mountPath: /var/cache/nginx
- name: nginx-root
mountPath: /var/run/nginx.pid
readOnly: true
volumes:
- name: readonly-volume
emptyDir: {}
- name: nginx-root
emptyDir:
medium: "Memory"
And here is the running deployments and pods
controlplane ~ ➜ k -n sec-ns get deployments.apps,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 3/3 3 3 12s
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-8466cbb4cd-x4k6d 1/1 Running 0 12s
pod/nginx-deployment-8466cbb4cd-bc8qv 1/1 Running 0 12s
pod/nginx-deployment-8466cbb4cd-zfwxt 1/1 Running 0 12s
controlplane ~ ➜ k -n sec-ns get deployments.apps,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 3/3 3 3 15s
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-8466cbb4cd-x4k6d 1/1 Running 0 15s
pod/nginx-deployment-8466cbb4cd-bc8qv 1/1 Running 0 15s
pod/nginx-deployment-8466cbb4cd-zfwxt 1/1 Running 0 15s
You’re definitely getting the idea. I think that the nginx.pid file needs to be writable, but in any case, you now know why it wasn’t starting. Bravo!
Following what you just said about allowing the the nginx.pid file to be writeable. However, the requirements for the question I was solving stated that
Task: Modify Deployment nginx-deployment the sec-ns namespace as follows
• Start the container with a user ID of 1001
• Do not allow processes to gain privileges beyond those of their parents (disable allowPrivilegeEscalation).
• Load the container’s root filesystem as read-only (read-only permissions to the root file).
Please will my code block satisfy the above requirement if I set nginx.pid file to be writeable.
No, it’s consistent. The root file system is indeed read only. But you can mount writeable directories into the root file system so that the program works. As you’ve seen, nginx won’t load unless it can write its run-file and its cache. So you mount those. But everything else is read-only, as it should be.
For comparison, here’s my version of your final file:
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
name: nginx-deployment
namespace: sec-ns
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
volumes:
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
containers:
- image: nginx:1.14.2
name: nginx
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
resources: {}
volumeMounts:
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
status: {}
You can check it in the lab, and will see that it passes.
Thanks so much for for your explanation. The concepts is lots clearer to me now. I am super grateful. This is my first time of using the kodekloud community plaform. It’s just amazing.