Accessing Amazon DocumentDB from dockerized Java with TLS enabled
There is a good set of documentation available when developing with Amazon DocumentDB, including connecting programmatically with TLS enabled. There is a variety of languages covered there, including Java, but what I did not find was the steps to build a docker container where Java code would be able to connect to the Amazon DocumentDB.
Pre-requisites
- Have a DocumentDB cluster ready.
- Read the instructions for Java connecting with TLS enabled from the official AWS documentation.
- Additionally, make sure you can connect to your cluster using the
Main
class from the sample above (from your IDE).
For reference, see the whole sample project on GitHub.
Dockerizing Java with RDS CA in keystore
As described in the AWS documentation, Java code needs Amazon RDS CA certificate inside a trust store. In short, we will create the trust store when building the Docker image, bake it into the image, so that later the Java code running in that container can use it.
Creating a keystore JKS file
AWS documentation in Java connecting with TLS enabled provides a shell script that creates a trust store with the RDS CA certificate. We slightly modify that script to read the trust store password from an argument.
Let’s store the shell script next to the Dockerfile
that will:
- Start from
openjdk:12-alpine
- Install
curl
,openssl
, andperl
needed by the shell script - Read a docker argument
- Run the shell script to create the trust store
/certs/rds-truststore.jks
baked inside the image
FROM openjdk:12-alpine# Install needed packages
RUN apk update \
&& apk upgrade \
&& apk --no-cache add curl openssl perl# add truststore needed for connection to DocumentDB cluster
COPY import_rds_certs.sh /certs/import_rds_certs.sh
ARG trustStorePassword
RUN /certs/import_rds_certs.sh $trustStorePassword
Configure Java application
AWS documentation tells us to use the keystore
in your program by setting the following system properties in your application before making a connection to the Amazon DocumentDB cluster.
javax.net.ssl.trustStore: <truststore>
javax.net.ssl.trustStorePassword: <truststorePassword>
You can use the JavaMain
class showed in the AWS documentation to connect to the cluster.
See our modified Main.java where we will set the SSL system properties using -D
flags. Don’t forget to configure your cluster hostname, user, password, database, and collection in the code of Main.java
. For running the jar from the docker, we will finalize the Dockerfile
with:
ENV TRUST_STORE_PASSWORD=$trustStorePassword# copy app
COPY build/libs/java-docker-rds.jar /java-docker-rds.jarCMD java -Djavax.net.ssl.trustStore=/certs/rds-truststore.jks -Djavax.net.ssl.trustStorePassword=$TRUST_STORE_PASSWORD -jar java-docker-rds.jar
Build the Docker image
When building the image, we will provide the trustStorePassword
in --build-arg
.
docker build --tag my-prj/service:0.0.0-local --build-arg trustStorePassword=somePassword .
Run the container
Simply run using the image we have just built:
docker run abcdef12345
This should output the number of entries in your collection.
Troubleshooting
At first, make it connect from your IDE
When running into problems, first make sure you can run the Main.java
from your IDE and connect to the cluster using -Djavax.net.ssl.trustStore
and -Djavax.net.ssl.trustStorePassword
. Notice, for that you will need to have the trust store JKS file locally on your laptop — use the shell script from AWS Documentation to create it. It is better to troubleshoot and debug in your IDE, get familiar with the setup, and then proceed with the Docker container.
UnrecoverableKeyException: Password verification failed
Together with IOException: Keystore was tampered with, or password was incorrect
usually means that you did not point javax.net.ssl.trustStore
correctly to the JKS file. Remember that when running from your IDE, the path is on your disk. But when running in the Docker container, it is the path inside that container — /certs/rds-truststore.jks
in our sample project.
UnrecoverableKeyException: failed to decrypt safe contents entry
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
In the stack trace, you will also see IOException: keystore password was incorrect
and that it exactly it — you did not provide the correct password in javax.net.ssl.trustStorePassword
.