Reputation: 1746
I set the securityContext to run as a different User as definded in the Docker Image, but it still gets deployed and the App starts without problems.
Shouldn't it be failing or do I get something wrong here?
I am using GKE and Helm. Kubernetes 1.22
Dockerfile:
FROM openjdk:17-alpine as java17
FROM alpine:3.15.4
COPY --from=java17 /opt/openjdk-17 /opt/openjdk-17
ENV JAVA_HOME=/opt/openjdk-17
ENV PATH=$PATH:${JAVA_HOME}/bin
ARG JAVA_FILE="1.0-SNAPSHOT"
RUN apk add --no-cache java-cacerts && addgroup -S 10033 && adduser -S 10033 -G 10033
USER 10033:10033
COPY --chown=10033:10033 ${JAVA_FILE} /opt/app/app.jar
ENTRYPOINT ["java","-jar","/opt/app/app.jar", "$JVM_OPTS"]
Deployment:
containers:
- name: "myproject"
image: "eu.gcr.io/mycompany/myproject:1.0"
imagePullPolicy: "IfNotPresent"
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
privileged: false
runAsUser: 10005
runAsGroup: 20050
runAsNonRoot: true
kubectl version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.5", GitCommit:"5c99e2ac2ff9a3c549d9ca665e7bc05a3e18f07e", GitTreeState:"clean", BuildDate:"2021-12-16T08:38:33Z", GoVersion:"go1.16.12", Compiler:"gc", Platform:"windows/amd64"}
Server Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.7-gke.1500", GitCommit:"565bc494bfc66bfb42aec331000c61f72b020f1a", GitTreeState:"clean", BuildDate:"2022-03-10T09:33:51Z", GoVersion:"go1.16.14b7", Compiler:"gc", Platform:"linux/amd64"}
EDIT:
I have build the image with root user and it still works.
/opt/app $ ls -la
total 73024
drwxr-xr-x 2 root root 4096 May 20 12:03 .
drwxr-xr-x 1 root root 4096 May 20 12:04 ..
-rw-r--r-- 1 root root 74765459 May 20 12:01 app.jar
I also check the following and somehow its working, but strange is that the app.jar, which is owned by root, can be executed. I think I am missing some concepts here.
So it would be possible to run any image as a specific user set from outside, which is very cool. Its kind a magic for me, so maybe someone can explain how this works?
/ $ id
uid=10005 gid=20050 groups=101(20050)
/ $ ps aux
PID USER TIME COMMAND
1 10005 0:40 java -jar /opt/app/app.jar $JVM_OPTS
45 10005 0:00 sh
61 10005 0:00 ps aux
Upvotes: 0
Views: 663
Reputation: 159855
Files are typically world-readable, unless you explicitly set otherwise. Your ls -l
output shows that too: in the output -rw-r--r--
, the file (leading -
) is readable and writable but not executable by its owner (rw-
), and readable but not writeable or executable by its group owner (r--
) and also anyone else (r--
).
This means that it doesn't actually matter which user owns the jar file. You generally don't want your application code to be writable by the user that's running it, lest a bug causes it to be modified at runtime. I'd suggest it's a good practice to have your application code owned by root, and not writable by other users.
# without a --chown option, so it's owned by root
COPY ${JAVA_FILE} /opt/app/app.jar
# change users as the last thing in your Dockerfile
USER 10333
CMD ["java", "-jar", "/opt/app/app.jar"]
If your application needs to write data inside its container, first consider if it can write it elsewhere like a database. This is doubly true on Kubernetes where you frequently will have multiple replicas of a pod and pods can be deleted outside your control. If you really do need container-local state, keep it in a single directory; make that one directory owned by the default container user in the Dockerfile; and mount a volume over that directory when you run the container (in Kubernetes, via a StatefulSet).
Upvotes: 1