TL;DR: After installing my CA in a Docker container from image eclipse-temurin:8-jre-alpine
I still get javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure when accessing an URL with a certificate signed by the CA.
I’m currently trying to upgrade one of my applications from base image openjdk:8-jre-alpine
(which was last updated three years ago and still runs Java 1.8.0_212
) to eclipse-temurin:8-jre-alpine
(with Java 1.8.0_332
).
I’m using self-signed certificates for some other applications that this application communicates with. So in the current setup I copy my CA-certificate to /usr/local/share/ca-certificates
and call update-ca-certificates
.
In eclipse-temurin:8-jre-alpine
I have to do some more steps: The package ca-certificates
is not installed by default. Also the package java-cacerts
is not installed anymore (which makes sense when ca-certificates
is not, of course). So in my Dockerfile I install both and also link the cacerts
file, that is created by java-cacerts
, to the Java home directory:
apk add -U ca-certificates java-cacerts && ln -sf /etc/ssl/certs/java/cacerts $JAVA_HOME/lib/security/
Afterwards I copied my CA certificate to /usr/local/share/ca-certificates/
and called update-ca-certificates
. When I look at /etc/ssl/certs/
I see the link to my certificate in there. And the file /etc/ssl/certs/java/cacerts
is also updated (at least the modification date changes).
Accessing any application with a certificate signed by the CA works with wget
now. But still fails from a Java application.
If I do the exact same thing with the image eclipse-temurin:11-jre-alpine
it works in Java as well.
Any help is much appreciated!
How I Tested
- start a container from image
eclipse-temurin:8-jre-alpine
docker run --rm -it --name temurin_8alpine_test --entrypoint /bin/sh eclipse-temurin:8-jre-alpine
- install
ca-certificates
andjava-cacerts
in container
apk add -U ca-certificates java-cacerts && ln -sf /etc/ssl/certs/java/cacerts $JAVA_HOME/lib/security/
- copy certificate to running container
docker cp /path/to/my/CA-certificate.pem temurin_8alpine_test:/usr/local/share/ca-certificates/
- update certificate stores in container
update-ca-certificates
this warns ca-certificates.crt does not contain exactly one certificate or CRL: skipping, which is ok (https://github.com/gliderlabs/docker-alpine/issues/30)
- test with
wget
/ # wget https://my.internal.app
Connecting to my.internal.app (1.2.3.4:443)
saving to 'index.html'
index.html 100% |**********************************************************| 1087 0:00:00 ETA
'index.html' saved
- download, compile and upload
SSLPoke
wget -q https://confluence.atlassian.com/download/attachments/117455/SSLPoke.java -O /tmp/SSLPoke.java
# make sure to use Java 8 compiler or use --target 8
javac /tmp/SSLPoke.java -d /tmp/
docker cp /tmp/SSLPoke.class temurin_8alpine_test:/
SSLPoke from https://matthewdavis111.com/java/poke-ssl-test-java-certs/
- test with
SSLPoke
in container
/ # java SSLPoke google.com 443
Successfully connected
/ # java SSLPoke my.internal.app 443
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alert.createSSLException(Alert.java:131)
at sun.security.ssl.Alert.createSSLException(Alert.java:117)
at sun.security.ssl.TransportContext.fatal(TransportContext.java:311)
at sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:293)
at sun.security.ssl.TransportContext.dispatch(TransportContext.java:185)
at sun.security.ssl.SSLTransport.decode(SSLTransport.java:152)
at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1397)
at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1305)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:440)
at sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:818)
at sun.security.ssl.SSLSocketImpl.access$200(SSLSocketImpl.java:73)
at sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:1180)
at sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:1152)
at SSLPoke.main(SSLPoke.java:23)
/ #
2
Answers
After some deeper digging and some help by @JockX I found the actual issue: Java8 Temurin does not support any of the SSL cipher suites my internal app requires.
As the same goes for @JockX's example https://jockx.net I'll use that site for the example:
All ciphers supported by the site use eliptic curves:
When you look at the supported cipher suites of the Java installation in a container running with image
eclipse-temurin:8-jre-alpine
, then you get the following:I compiled the following short script with Java 8 and copied it to the container:
If I do the same in a container running with image
eclipse-temurin:11-jre-alpine
I get the following:https://www.google.com supports a lot more ciphers and hence accessing it works from
eclipse-temurin:8-jre-alpine
Thanks for your support!
Forget about ca-cert related packages, and directly update
cacerts
file of JRE powering the container. Usekeytool
, which is part of the image you are using:Depending on the format of the ca-certificate file you are adding, you may need to convert it to the format supported by
keytool
. For example a PEM file with the lines like these:may be converted with
openssl
:If to be done inside the container, the requrired package is
openssl
: