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.
- 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
Mainclass 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
perlneeded by the shell script
- Read a docker argument
- Run the shell script to create the trust store
/certs/rds-truststore.jksbaked 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
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.
You can use the Java
Main 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
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
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.
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.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
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