adoptium / containers

Repo containing the dockerfiles and scripts to produce the official eclipse-temurin containers.
https://hub.docker.com/_/eclipse-temurin/
Apache License 2.0
206 stars 88 forks source link

[Bug]: internal CA certificate mechanism does not work with non-root user #464

Closed gaeljw closed 1 month ago

gaeljw commented 7 months ago

Please add the exact image (with tag) that you are using

eclipse-temurin:11-jre-jammy

Please add the version of Docker you are running

N/A

What happened?

As per the documentation "Can I add my internal CA certificates to the truststore?" and following implementation of https://github.com/adoptium/containers/issues/293 and https://github.com/adoptium/containers/pull/392, I wanted to mount my internal CA certificate in a container at runtime.

The issue is that the internal CA certificate is not taken into account, an error is raised at start time:

cp: cannot create regular file '/usr/local/share/ca-certificates/mycert.pem': Permission denied

From my first investigation, this is related to the fact that we use a non-root user whereas the internal CA handling can only work if the running user is root.

Simplified Dockerfile:

FROM eclipse-temurin:11-jre-jammy

RUN addgroup --system my_user && adduser --system --shell /bin/false --no-create-home --ingroup my_user --uid 999 my_user
USER 999

WORKDIR /app

# Copy some JAR file in /app/lib

CMD java -cp "/app/conf:/app/lib/* "my.package.MyMainClass"

And run with the following command:

podman run -v ./mycert.pem:/certificates/mycert.pem -e USE_SYSTEM_CA_CERTS=1 myImageName

Commenting out the directive to run as non-root makes it work.

In a Kubernetes context where non-root is enforced, it makes the feature unusable.

However I don't know if this even possible to make it work as non-root. If not, I guess we should at least document it.

Relevant log output

No response

gaeljw commented 7 months ago

In the meantime, we switched to use the "good old" way of configuring the trustore with a java opt -Djavax.net.ssl.trustStore=/certificates/bundle.jks and mounting a JKS rather than the PEM file.

gdams commented 7 months ago

@rassie any ideas?

rassie commented 7 months ago

It's a good thing this feature is opt-in, I guess. Kubernetes being mostly non-root is a good point which I didn't have in mind when developing the PR.

Currently, we are explicit about using system CA store for JRE's trust store, just like openjdk images used to do. This is basically a two-step-process: add certificates to system CA store first and then use those certificates in JRE store. The first step is inherently something that requires root permissions, since we are updating a system CA store. The second step also currently requires root user, since the /opt/java/openjdk/lib/security/cacerts file belongs to root and thus cannot be updated by user.

Both steps should still probably be possible in a non-privileged container -- there are valid reasons for updating the system CA store even without any JRE context and same reasons are valid for updating JRE's trust store. I'm not quite sure what would be the best way to proceed, but at least for the latter part, creating and using a trust store at a different filesystem location could be the way, but it doesn't help with system CA store.

danielthieleog commented 7 months ago

Workaround: You could additionally install a tool like su-exec in the docker image and prepend it to the command. You would run the container as root. It updates certificates running the default entrypoint. Then the command starts your application with su-exec with user and group whatever you want.