Tim Schwalbe
Tim Schwalbe

Reputation: 1746

Pod is not failing when building Alpine Container Image with different user than specified in container securityContext

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

Answers (1)

David Maze
David Maze

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

Related Questions