0

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?

Matt Raible
  • 8,187
  • 9
  • 61
  • 120
  • Does your certificate have the appropriate CN and SANs that matches your reality? You either need to install peers' certificates in each others trust stores, or generate a CA and derive your individual certificates from this CA, IMHO. – wilx Mar 05 '19 at 00:15
  • The mkcert documentation you linked to also mentions that it has a root CA certificate that it arranges to be trusted locally, but you'd have to copy that certificate into your images. – David Maze Mar 05 '19 at 03:06
  • I was able to solve it with the help of [this answer](https://stackoverflow.com/a/35304873/65681). I changed `ldap.cer` to `localhost.pem` and added `USER root` before it. – Matt Raible Mar 05 '19 at 04:30

0 Answers0