How to resolve PKIX Path Building Failed in Docker Container

Consider the following scenario. You are running a service in a docker container. This service calls another service in another docker container and the API calls fail with the following error:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

In this post, I will show how to resolve this issue with a simple fix.

This scenario is very common with microservices running in docker containers. Also there are few ways you can resolve this issue, but I will suggest a standard way to resolve this issue.

A standard solution is to get SSL certificate of target service and import that certificate in Keystore of Java runtime that calling service is using.

How do we do that with docker though?

The dilemma exists because every time you stop docker container and restart or kill a docker container and restart it, it will change container id. With that, you can’t be sure where JAVA_HOME of your calling service exists.

So depending on what Java environment are you using for your docker container, the easiest thing you can do is copy a cacerts keystore file from your localhost machine to docker container when building the docker image.

Before you copy cacerts, make sure you import the SSL certificate of the target service. You can use keytool command to import this certificate.

Now add a below command in your Dockerfile

COPY ./cacerts /usr/lib/jvm/java-1.8.0-amazon-corretto.x86_64/jre/lib/security/cacerts

This will build your docker image and will resolve the PKIX Path Building Failed error.

Drawback

A drawback of this solution is that you have to make sure that your base docker image has jvm path mentioned in the command. If it is different from above, you will have to first find that. Also if you call multiple services, you will have to get SSL certificates of all those services.

One important thing to note that this should not happen in your production environment, but mostly development sandbox. The production environment should have CA signed SSL certificates on the load balancer and all your services should be behind that load balancer while sharing the same certificate.

Let me know if this story helped you. You can contact me at @betterjavacode on twitter.