I have an HTTPS certificate that I generated with mkcert:
mkcert localhost 127.0.0.1 ::1 `hostname` discovery
I'm building a Spring-based microservices architecture using Spring Boot, Eureka, and Spring Cloud Config.
The hostname
is an argument that's necessary because my microservices make a request to my machine name instead of localhost when talking to the cloud config server.
I converted the resulting .pem
and key.pem
files to a .p12
file using OpenSSL:
openssl pkcs12 -export -in localhost.pem -inkey localhost-key.pem -out keystore.p12 -name bootifulsecurity
I can run all my apps with HTTPS if I set a bunch of environment variables.
export SERVER_SSL_ENABLED=true
export SERVER_SSL_KEY_STORE=../keystore.p12
export SERVER_SSL_KEY_STORE_PASSWORD=CL1649GH
export SERVER_SSL_KEY_ALIAS=bootifulsecurity
export SERVER_SSL_KEY_STORE_TYPE=PKCS12
This works great, and I'm able to communicate between services after setting the following properties in each microservice.
server.port=8080
eureka.instance.secure-port-enabled=true
eureka.instance.secure-port=${server.port}
Now I want to run this in Docker Compose. I have a Dockerfile
for each project that looks like this:
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD target/*.jar app.jar
ADD keystore.p12 keystore.p12
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
I use a .env
file for each service in docker-compose.yml
to set the same environment variables for each service.
SERVER_SSL_ENABLED=true
SERVER_SSL_KEY_STORE=keystore.p12
SERVER_SSL_KEY_STORE_PASSWORD=<hidden>
SERVER_SSL_KEY_ALIAS=bootifulsecurity
SERVER_SSL_KEY_STORE_TYPE=PKCS12
When I start everything, I can hit each endpoint from my browser, proving that the HTTPS cert is working for Spring Boot. However, I see the following in my logs whenever my services try to register with Eureka (at https://discovery:8761/eureka
).
Caused by: sun.security.validator.ValidatorException: PKIX path building
failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
I've tried using keytool
as part of the Dockerfile
, but that doesn't seem to solve the problem.
ADD localhost.pem $JAVA_HOME/jre/lib/security
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
RUN \
cd $JAVA_HOME/jre/lib/security \
&& keytool -keystore cacerts -storepass CL1649GH -noprompt -trustcacerts -importcert \
-alias bootifulsecurity -file localhost.pem
I've also tried converting from .pem
to .crt
and updating it this way:
ADD localhost.crt /usr/local/share/ca-certificates/localhost.crt
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
RUN update-ca-certificates
This doesn't solve the problem either. Any idea how to allow Docker images to talk to each other over HTTPS?