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
204 stars 87 forks source link

Rework CA certificate support to allow rootless containers #538

Closed rassie closed 1 month ago

rassie commented 2 months ago

This PR includes several improvements and simplifications in CA certificate handling.

Support for CA certificates in containers running as a non-root user

After this PR, CA certificates can get applied even if the container is run as an arbitrary user. This helps usage in restricted environments like Red Hat OpenShift and follows best practices for Kubernetes deployments. When running an Adoptium container as non-root user with USE_SYSTEM_CA_CERTS=1, only the JVM truststore will get updated (or more correctly: re-created), while system CA store will not get updated.

Support for CA certificates in containers running with read-only root filesystem

After this PR, CA certificates can get applied even if the container is run with a read-only root filesystem. Running containers with read-only root filesystem is a recommended best practice for Kubernetes. When running an Adoptium container with read-only root filesystem, the same restrictions apply as with non-root users. In addition, /tmp must be mounted as an EmptyDir volume, to allow JVM trust store to get updated.

Unification of Docker entrypoint scripts into one

Since we can't rely on system tools in non-root or read-only root filesystem mode, the certificate procedure has been unified between all Linux platforms and therefore there is now only one entrypoint script left. As a consequence, a conditional has been added in Dockerfile generation script to exclude Windows platforms, which currently do not support CA certificates.

Entrypoint script now exports CACERT environment variable to point to the used truststore file

Since the JVM truststore can't be overwritten, it needs to be recreated on a different path. This path is automatically provided via JAVA_TOOL_OPTIONS by the container entrypoint script, however it's also exported via the environment variable CACERT to facilitate re-use of that truststore in local scripts.

NB: Dockerfile updates are not included in this PR, since they will get updated by the script after the merge.

Docs updates at https://github.com/docker-library/official-images/ pending.

Possibly fixes: https://github.com/adoptium/containers/issues/464

rassie commented 2 months ago

It seems some tests are failing, which didn't fail locally. Let me look at it.

EDIT: Possibly the same problem as in the last PR on this topic: Dockerfiles are not current, so that the tests fail in the PR. Should I include the Dockerfile updates?

karianna commented 2 months ago

It seems some tests are failing, which didn't fail locally. Let me look at it.

EDIT: Possibly the same problem as in the last PR on this topic: Dockerfiles are not current, so that the tests fail in the PR. Should I include the Dockerfile updates?

I think you need to rebase in that case?

rassie commented 2 months ago

It seems some tests are failing, which didn't fail locally. Let me look at it. EDIT: Possibly the same problem as in the last PR on this topic: Dockerfiles are not current, so that the tests fail in the PR. Should I include the Dockerfile updates?

I think you need to rebase in that case?

That's no problem normally. I can try including them.

karianna commented 1 month ago

@rassie Are you able to address the feedback from @tianon (he's our partner from DockerHub :-)) in a separate PR?

rassie commented 1 month ago

@rassie Are you able to address the feedback from @tianon (he's our partner from DockerHub :-)) in a separate PR?

Yes, sure, should be possible in the next 24 hours or so.

rassie commented 1 month ago

@tianon @karianna I've been writing a comment addressing @tianon's point about scope creep and might have found a way to keep multiple sides happy, while reducing pain points, in particular:

I'm thinking about using a companion container image, maintained either inside or outside or Adoptium project, which would contain most of the logic in the current entrypoint and could be used as an init container.

It would work somewhat like this:

  1. Freeze and deprecate current entrypoint-based certificate implementation, add a deprecation warning
  2. Document the following recommended process:
    • First init-container: your eclipse-temurin-based target container; copy the cacerts file from it to a temporary volume
    • Second init-container: this new companion container, with your custom certificates and temporary volume mounted, which would combine both to a new cacerts using the logic in this PR
    • Main container: your eclipse-temurin-based target container with added volume mount containing the new cacerts file and an added environment variable JAVA_TOOL_OPTIONS=-Djavax.net.ssl.trustStore=/volume/cacerts -Djavax.net.ssl.trustStorePassword=changeit.
  3. At some point in the future: remove current certificate functionality, possibly remove the entrypoint altogether.

This would probably make the Kubernetes camp happy, since it directly maps onto Kubernetes proceedings. Docker camp would need something like docker compose with service_completed_successfully, but this is probably manageable.

Should I try and implement this before this PR is included in a released image?

rassie commented 1 month ago

Thinking further: if this companion image were to be maintained inside the Adoptium project, we might get away with just including the default cacerts and thus only needing one init container instead of two. No idea how dependant this is on the actual JRE version, maybe there is some common source for the cacerts file?

karianna commented 1 month ago

@tianon @karianna I've been writing a comment addressing @tianon's point about scope creep and might have found a way to keep multiple sides happy, while reducing pain points, in particular:

  • People feeling the scope creep and maintenance burden
  • People not liking the entrypoint requirement
  • People wanting to inject CA certificates into JRE trust stores.

I'm thinking about using a companion container image, maintained either inside or outside or Adoptium project, which would contain most of the logic in the current entrypoint and could be used as an init container.

It would work somewhat like this:

  1. Freeze and deprecate current entrypoint-based certificate implementation, add a deprecation warning
  2. Document the following recommended process:

    • First init-container: your eclipse-temurin-based target container; copy the cacerts file from it to a temporary volume
    • Second init-container: this new companion container, with your custom certificates and temporary volume mounted, which would combine both to a new cacerts using the logic in this PR
    • Main container: your eclipse-temurin-based target container with added volume mount containing the new cacerts file and an added environment variable JAVA_TOOL_OPTIONS=-Djavax.net.ssl.trustStore=/volume/cacerts -Djavax.net.ssl.trustStorePassword=changeit.
  3. At some point in the future: remove current certificate functionality, possibly remove the entrypoint altogether.

This would probably make the Kubernetes camp happy, since it directly maps onto Kubernetes proceedings. Docker camp would need something like docker compose with service_completed_successfully, but this is probably manageable.

Should I try and implement this before this PR is included in a released image?

I'd probably split this into it's own issue and we can build ontop of what we've already merged here.