-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change images to run as non-root user by default #45
Conversation
Currently the container images is running as root user as follows. And it is recommended to run as non-root user for the security purpose. In fact, following log will be seen at the startup time of Spring Boot. ```text 2022-10-20 17:32:02.045 INFO 1 --- [ main] com.yoshio3.HelloSampleApplication : Starting HelloSampleApplication v0.0.1-SNAPSHOT using Java 17.0.4.1 on 7446eed214e7 with PID 1 (/app/app.jar started by root in /app) ``` If we use this fix, the application will run as non-root user ("javauser") by default like follows. ```text 2022-10-20 17:30:28.103 INFO 1 --- [ main] com.yoshio3.HelloSampleApplication : Starting HelloSampleApplication v0.0.1-SNAPSHOT using Java 17.0.4.1 on 9a2adf159e03 with PID 1 (/app/app.jar started by javauser in /app) ``` In order to run the container more secure, this pull request will be useful. And if this pull request is not included, every user need to write look like following Dockerfile to run as non-root user ```Dockerfile ################################################################## # Stage 1: Create User and Group ################################################################## FROM mcr.microsoft.com/cbl-mariner/base/core:2.0 AS CREATE-DEPENDS-FILES RUN mkdir /staging \ && mkdir /staging/etc \ && tdnf install -y --releasever=2.0 shadow-utils \ && groupadd --system -g 101 java-app \ && useradd -u 101 -g java-app --shell /bin/false --home-dir /dev/null --system javausers \ && tdnf clean all \ # Copy user/group info to staging && cp /etc/passwd /staging/etc/passwd \ && cp /etc/group /staging/etc/group ################################################################## # Stage 2: Create User and Group ################################################################## FROM mcr.microsoft.com/openjdk/jdk:17-distroless COPY --from=CREATE-DEPENDS-FILES /staging/ / USER javauser WORKDIR /app ENV LANG='ja_JP.UTF-8' LANGUAGE='ja_JP:ja' LC_ALL='ja_JP.UTF-8' ENV TZ='Asia/Tokyo' ENV JAVA_HOME=/app COPY ./target/hello-sample-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT ["java","-Xmx1g","-XX:+UseParallelGC","-XX:MaxRAMPercentage=75","-jar","/app/app.jar"] EXPOSE 8080 ```
Thank you for the PR and the suggestion. We'll discuss it internally but I suspect that this particular implementation (of adding a MSFT provided @brunoborges - thoughts? |
Some people may want to run a server on port 80 inside the container. And for that to work, the JVM must be running as root. So, to cover all scenarios, we've decided to go with root. But as Martijn pointed out, customers are more than welcome to customize their layer as they write their own Dockerfiles, and configure a non-root user. Indeed, our documentation does not cover this well, and we should at the very least, explain which user it runs by default, and how to customize that on a downstream Docker image layer built by customers. |
Running as root is usually seen as a bad practice ( there is tons of documentation on this, https://sysdig.com/blog/dockerfile-best-practices/ for example), so I believe it should be the other way around : non-root by default, then users can reconfigure this as root if they have specific needs. |
@karianna san, @brunoborges san
Yes, if the customer can choose the At first, I created the following Dockerfile and build the images. FROM mcr.microsoft.com/openjdk/jdk:17-distroless
USER javauser
WORKDIR /app
ENV LANG='ja_JP.UTF-8' LANGUAGE='ja_JP:ja' LC_ALL='ja_JP.UTF-8'
ENV TZ='Asia/Tokyo'
ENV JAVA_HOME=/app
COPY ./target/hello-sample-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-Xmx1g","-XX:+UseParallelGC","-XX:MaxRAMPercentage=75","-jar","/app/app.jar"]
EXPOSE 8080 Then, If I run the above images, the following error happens. > docker run -p 8080:8080 -it tyoshio2002/sample1:1.1
docker: Error response from daemon: unable to find user javauser: no matching entries in passwd file. Even though the container builds success, the above "javauser" was not added to the container. Because the "CBL-Mariner" image doesn't have "useradd,groupadd" command by default and failed. Perhaps, many users would like to run the container as "non-root" users because it is the best practice that @jdubois san mentioned above.
To avoid confusion and every user must do the above, I created the pull request. If you decide to run the container as root, at least we should explain how to customize the USER in the official document. And I would like to ask you to do it please. BTW, I already wrote it by Japanese as follows. |
@yoshioterada - As a side note - the GH Actions are failing. I'm not sure if this is due to the #comment you've added in the middle of the user setup logic in the PR. |
if we make the change then I think moving to non-root as a default will be a breaking change for existing customers who are using these images, something we need to keep in mind. |
Java Version updated
During the build images in the GitHub Actions, Following error had showed and failed to build the images. ```text Step 1/18 : ARG INSTALLER_IMAGE="mcr.microsoft.com/cbl-mariner/base/core" Step 2/18 : ARG INSTALLER_TAG="2.0" Step 3/18 : ARG BASE_IMAGE="mcr.microsoft.com/cbl-mariner/distroless/base" Step 4/18 : ARG BASE_TAG="2.0" invalid reference format Step 5/18 : FROM ${INSTALLER_IMAGE}:${INSTALLER_TAG} AS installer ```
create test work flow
This reverts commit 06739f6.
@karianna san, For the GitHub Action failed issue. It may be due to the workflow as a docker build
-t mcr.microsoft.com/openjdk/jdk:${{ matrix.jdkversion }}-${{ matrix.baseimage }}
-f ./docker/${{ matrix.baseimage }}/Dockerfile.msopenjdk-${{ matrix.jdkversion }}-jdk
./docker/${{ matrix.baseimage }}/
--build-arg INSTALLER_IMAGE=${{ env.INSTALLER_IMAGE }}
--build-arg INSTALLER_TAG=${{ matrix.installer_tag }}
--build-arg BASE_IMAGE=${{ env.BASE_IMAGE }}
--build-arg BASE_TAG=${{ matrix.base_tag }} And from the result of the GitHub Action, the following was invoked. Run docker build
-t mcr.microsoft.com/openjdk/jdk:11-mariner
-f ./docker/mariner/Dockerfile.msopenjdk-11-jdk
./docker/mariner/
--build-arg IMAGE=
--build-arg TAG='2.0' At that time, the following error happened.
In my local environment, I tried to execute the above command, then the same error happened. > docker build -t mcr.microsoft.com/openjdk/jdk:11-mariner -f ./docker/mariner/Dockerfile.msopenjdk-11-jdk \
./docker/mariner/ --build-arg IMAGE= --build-arg TAG='2.0'
[+] Building 0.1s (2/2) FINISHED
=> [internal] load build definition from Dockerfile.msopenjdk-11-jdk 0.0s
=> => transferring dockerfile: 819B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
failed to solve with frontend dockerfile.v0: failed to create LLB definition: failed to parse stage name ":2.0": invalid reference format However, if I invoke the following command that includes docker build
-t mcr.microsoft.com/openjdk/jdk:11-mariner
-f ./docker/mariner/Dockerfile.msopenjdk-11-jdk
./docker/mariner/
--build-arg IMAGE="mcr.microsoft.com/cbl-mariner/base/core"
--build-arg TAG='2.0' And also, if I updated the "Java Version" to the latest version in the > docker images | grep openjdk
REPOSITORY TAG IMAGE ID CREATED SIZE
mcr.microsoft.com/openjdk/jdk 17-ubuntu 36257b9063c9 3 minutes ago 420MB
mcr.microsoft.com/openjdk/jdk 11-ubuntu e3e8059f2b98 4 minutes ago 405MB
mcr.microsoft.com/openjdk/jdk 17-mariner-cm1 08097df5a446 5 minutes ago 587MB
mcr.microsoft.com/openjdk/jdk 11-mariner-cm1 eda8f1738478 6 minutes ago 585MB
mcr.microsoft.com/openjdk/jdk 8-mariner 43cfb9675c4a 8 minutes ago 301MB
mcr.microsoft.com/openjdk/jdk 17-mariner e21f25855e93 9 minutes ago 380MB
mcr.microsoft.com/openjdk/jdk 11-mariner 66a903eb3d45 9 minutes ago 378MB
mcr.microsoft.com/openjdk/jdk 8-distroless d7b053ea4be5 10 minutes ago 232MB
mcr.microsoft.com/openjdk/jdk 17-distroless a6360cfe9fcd 17 minutes ago 342MB
mcr.microsoft.com/openjdk/jdk 11-distroless d9de552e9e4a 17 minutes ago 327MB It seems that it looks like a similar issue as follows. |
Deleted test-yaml file
@d3r3kk - Can we get one of the infra folks to look at this? |
@yoshioterada do you have some customer feedback to share, where they have concrete security concerns about this image being root by default? |
There is plenty of documentation telling not to run containers as root, but probably the best argument is that you cannot run containers as root on OpenShift ( see https://dev.to/ksingh7/allow-containers-to-run-as-root-on-openshift-4-hack-3gp7 for example), so our image wouldn't work on ARO. |
In some situation, UID 101 may be used. In order to prevent conflicts. I changed the UID.
After applied this pull request, the application will run as "javauser". However there is no directory which has "write permission". If one Java Application try to write some file in the deployment directory, it will fail. Because it is owned by root user. So in order write some file from the application, I added a default directory which owned by the "javauser" So if user deployment their application under the "/app" directory. The application will run without problem. If the user uses the Mariner core image, then there is "chown" command in the container images. So user can create any directory and can change the owner. However "the distress image" doesn't have the "chown" command on the image nor shell. So we should mentioned the restriction for "distress image" users. For example, following explanation will be needed. ``` COPY --chown=2000:2000 artifact.jar /app/ ```
Dear Bruno-san. I'm sorry that I don't have any customers now. And today, I noticed one more thing. After applying this pull request, the application will run as "javauser". However, no directory has "write permission". If one Java Application tries to write some file in the deployment directory, it will fail. Because it is owned by the root user. So to write some files from the application, I added a So if the user deployment their application under the "/app" directory. The application will run without a problem. If the user uses the Mariner core image, then there is "chown" command in the container images. However, the "distress image" doesn't have the "chown" command on the image or shell. So we should mention the restriction for "distress image" users. For example, the following explanation will be needed. If you use the "distress image", please copy the artifact file under the "/app" directory with the following option.
|
Created a Bug for the infra team to follow up on. |
Thanks @yoshioterada. I've submitted PR #57 as a solution to this problem. The intent is that images will continue to run as root by default, but with the option that the user/customer may run as a non-root user, with the Let me know what you think of that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is likely we will close this one in favour of #57. By adding a non-root user to the images, customers will have the option to run their applications as non-root.
Daer @brunoborges san, I saw the new pull request as follows. GitHub : Add non-root user 'app' to all images #57 If you provide a default Application "app" user and the directory owned by the user, it may be helpful for the developers. There is no info now on learn.microsoft.com. So please write an explanation of how to use the "app" user in the customer's application. Then please close this pull request. |
Currently, the container images are running as root user as follows.
And I hope that it will run as a non-root user by default for security purposes.
The following log will be seen at the startup time of Spring Boot.
"/app/app.jar started by root" was wrote.
If we use this fix, the application will run as a non-root user ("javauser") by default as follows.
"/app/app.jar started by javauser" was wrote.
To run the container more securely, this pull request will be useful. And if this pull request is not included, every user needs to write a look like the following Dockerfile to run as a non-root user