Browse Source

Improve Docker image's cacert scripting (#81659)

Apply suggestions from Docker Inc about how to update the `cacerts` in
our Ubuntu-based Docker image. Instead of copying around files and
symlinking, instead install `ca-certificates` and `p11-kit`, and use the
latter to regenerate Java's `cacerts`, as well as ensuring it is
regenerated if the system ca certs are updated.
Rory Hunter 3 years ago
parent
commit
91b4f6ebdc

+ 18 - 14
distribution/docker/src/docker/Dockerfile

@@ -68,7 +68,7 @@ RUN chmod 0555 /bin/tini
 
 # Install required packages to extract the Elasticsearch distribution
 <% if (docker_base == 'default' || docker_base == 'cloud') { %>
-RUN <%= retry.loop(package_manager, "${package_manager} update && DEBIAN_FRONTEND=noninteractive ${package_manager} install -y curl ca-certificates-java") %>
+RUN <%= retry.loop(package_manager, "${package_manager} update && DEBIAN_FRONTEND=noninteractive ${package_manager} install -y curl ") %>
 <% } else { %>
 RUN <%= retry.loop(package_manager, "${package_manager} install -y findutils tar gzip") %>
 <% } %>
@@ -194,11 +194,12 @@ RUN ${package_manager} update --setopt=tsflags=nodocs -y && \\
 RUN <%= retry.loop(
     package_manager,
       "export DEBIAN_FRONTEND=noninteractive && \n" +
-      "${package_manager} update && \n" +
-      "${package_manager} upgrade -y && \n" +
-      "${package_manager} install -y --no-install-recommends curl netcat zip unzip vim-tiny ${docker_base == 'cloud' ? 'wget' : '' } && \n" +
-      "${package_manager} clean && \n" +
-      "rm -rf /var/lib/apt/lists/*"
+      "      ${package_manager} update && \n" +
+      "      ${package_manager} upgrade -y && \n" +
+      "      ${package_manager} install -y --no-install-recommends \n" +
+      "        ca-certificates curl netcat p11-kit unzip vim-tiny zip ${docker_base == 'cloud' ? 'wget' : '' } && \n" +
+      "      ${package_manager} clean && \n" +
+      "      rm -rf /var/lib/apt/lists/*"
   ) %>
 
 <% } else { %>
@@ -207,7 +208,7 @@ RUN <%= retry.loop(
     package_manager,
       "${package_manager} update --setopt=tsflags=nodocs -y && \n" +
       "      ${package_manager} install --setopt=tsflags=nodocs -y \n" +
-      "      nc shadow-utils zip unzip findutils procps-ng && \n" +
+      "        nc shadow-utils zip unzip findutils procps-ng && \n" +
       "      ${package_manager} clean all"
     ) %>
 
@@ -228,15 +229,11 @@ RUN groupadd -g 1000 elasticsearch && \\
 ENV ELASTIC_CONTAINER true
 
 WORKDIR /usr/share/elasticsearch
-COPY --from=builder --chown=0:0 /usr/share/elasticsearch /usr/share/elasticsearch
 
+COPY --from=builder --chown=0:0 /usr/share/elasticsearch /usr/share/elasticsearch
 COPY --from=builder --chown=0:0 /bin/tini /bin/tini
 COPY --from=zlib --chown=0:0 /usr/local/cloudflare-zlib /usr/local/cloudflare-zlib
 
-<% if (docker_base == 'default' || docker_base == 'cloud') { %>
-COPY --from=builder --chown=0:0 /etc/ssl/certs/java/cacerts /etc/ssl/certs/java/cacerts
-<% } %>
-
 <% if (docker_base == 'cloud') { %>
 COPY --from=builder --chown=0:0 /opt /opt
 <% } %>
@@ -260,11 +257,18 @@ COPY ${bin_dir}/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
 RUN chmod g=u /etc/passwd && \\
     chmod 0555 /usr/local/bin/docker-entrypoint.sh && \\
     find / -xdev -perm -4000 -exec chmod ug-s {} + && \\
-    ln -sf <%= docker_base == 'default' || docker_base == 'cloud' ? '/etc/ssl/certs/java/cacerts' : '/etc/pki/ca-trust/extracted/java/cacerts' %> \\
-      /usr/share/elasticsearch/jdk/lib/security/cacerts && \\
     chmod 0775 /usr/share/elasticsearch && \\
     chown elasticsearch bin config config/jvm.options.d data logs plugins
 
+<% if (docker_base == 'default' || docker_base == 'cloud') { %>
+# Update "cacerts" bundle to use Ubuntu's CA certificates (and make sure it
+# stays up-to-date with changes to Ubuntu's store)
+COPY bin/docker-openjdk /etc/ca-certificates/update.d/docker-openjdk
+RUN /etc/ca-certificates/update.d/docker-openjdk
+<% } else { %>
+RUN ln -sf /etc/pki/ca-trust/extracted/java/cacerts /usr/share/elasticsearch/jdk/lib/security/cacerts
+<% } %>
+
 EXPOSE 9200 9300
 
 <% if (docker_base != 'iron_bank') { %>

+ 13 - 0
distribution/docker/src/docker/bin/docker-openjdk

@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -Eeuo pipefail
+
+# Update "cacerts" bundle to use Ubuntu's CA certificates (and make sure it
+# stays up-to-date with changes to Ubuntu's store)
+
+trust extract \
+  --overwrite \
+  --format=java-cacerts \
+  --filter=ca-anchors \
+  --purpose=server-auth \
+  /usr/share/elasticsearch/jdk/lib/security/cacerts

+ 5 - 0
docs/changelog/81659.yaml

@@ -0,0 +1,5 @@
+pr: 81659
+summary: Improve Docker image's cacert scripting
+area: Packaging
+type: enhancement
+issues: []

+ 4 - 6
qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java

@@ -376,9 +376,11 @@ public class DockerTests extends PackagingTestCase {
         final String path = sh.run("realpath jdk/lib/security/cacerts").stdout;
 
         if (distribution.packaging == Packaging.DOCKER_UBI || distribution.packaging == Packaging.DOCKER_IRON_BANK) {
+            // In these images, the `cacerts` file ought to be a symlink here
             assertThat(path, equalTo("/etc/pki/ca-trust/extracted/java/cacerts"));
         } else {
-            assertThat(path, equalTo("/etc/ssl/certs/java/cacerts"));
+            // Whereas on other images, it's a real file so the real path is the same
+            assertThat(path, equalTo("/usr/share/elasticsearch/jdk/lib/security/cacerts"));
         }
     }
 
@@ -386,12 +388,8 @@ public class DockerTests extends PackagingTestCase {
      * Checks that there are Amazon trusted certificates in the cacaerts keystore.
      */
     public void test041AmazonCaCertsAreInTheKeystore() {
-        final String caName = distribution.packaging == Packaging.DOCKER_UBI || distribution.packaging == Packaging.DOCKER_IRON_BANK
-            ? "amazonrootca"
-            : "amazon_root_ca";
-
         final boolean matches = sh.run("jdk/bin/keytool -cacerts -storepass changeit -list | grep trustedCertEntry").stdout.lines()
-            .anyMatch(line -> line.contains(caName));
+            .anyMatch(line -> line.contains("amazonrootca"));
 
         assertTrue("Expected Amazon trusted cert in cacerts", matches);
     }