Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS DocumentDB TLS connection with Java

I am facing problems connecting with my DocumentDB cluster with plain Java over TLS/SSL

The procedure I followed as per the AWS docs is this:

I downloaded the .pem file from AWS and copied in the root of my java project, from where I executed:

keytool -importcert -trustcacerts -file rds-combined-ca-bundle.pem -alias certAlias -keystore rds-ca-certs -storepass keyStorePassword

This has created the rds-ca-certsat the root of my project which now looks like this:

enter image description here

And, the java code in Main.java is:

package com.example.documentdb;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.ServerAddress;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoCollection;
import org.bson.Document;


public final class Main {
    private Main() {
    }
    public static void main(String[] args) {

        String template = "mongodb://%s:%s@%s/test?ssl=true&replicaSet=rs0&readpreference=%s";
        String username = "myUsernameInCluster";
        String password = "myPasswordInCluster";
        String clusterEndpoint = "mycluster.node.us-east-1.docdb.amazonaws.com:27017";
        String readPreference = "secondaryPreferred";
        String connectionString = String.format(template, username, password, clusterEndpoint, readPreference);

        String keystore = "rds-ca-certs";
        String keystorePassword = "keyStorePassword";

        System.setProperty("javax.net.ssl.trustStore", keystore);
        System.setProperty("javax.net.ssl.trustStorePassword", keystorePassword);

        MongoClientURI clientURI = new MongoClientURI(connectionString);
        MongoClient mongoClient = new MongoClient(clientURI);

        MongoDatabase testDB = mongoClient.getDatabase("test");
        MongoCollection<Document> numbersCollection = testDB.getCollection("numbers");

        Document doc = new Document("name", "pi").append("value", 3.14159);
        numbersCollection.insertOne(doc);

        MongoCursor<Document> cursor = numbersCollection.find().iterator();
        try {
            while (cursor.hasNext()) {
                System.out.println(cursor.next().toJson());
            }
        } finally {
            cursor.close();
        }

    }
}

It gives me this ugly error:

com.mongodb.MongoSocketWriteException: Exception sending message

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

Interestingly, when I use the mongo CLI to connect over SSL/TLS, like this:

mongo --ssl --host mycluster.node.eu-central-1.docdb.amazonaws.com:27017 --sslCAFile rds-combined-ca-bundle.pem --username myUsernameInCluster --password myPasswordInCluster

It works perfectly, so I have discarded a networking issue and I think the problem is in the Java code itself or in the keytool command executed.

Additionally, with TLS disabled in the cluster this java code provided by AWS (that only differs in the keystore configuration) works.

PD: I know there are a bunch of other questions regarding SSL/TLS connection with AWS DocumentDB, but none of them address my issue specifically. Moreover, I have also checked plain mongodb TLS/SSL connection questions and the process differ so they are not valid for me.

like image 392
Arcones Avatar asked Jan 14 '20 17:01

Arcones


2 Answers

The issue seems to be related to the process of importing the certificates within the bundle, under the same alias.

So I have had to stop using the bundled option (rds-combined-ca-bundle.pem) and start using this one rds-ca-2019-root.pem

After importing the keystore using the following command:

keytool -importcert -trustcacerts -file rds-ca-2019-root.pem -alias rds19 -keystore rds-ca-certs -storepass keyStorePassword

Connectivity with the database under TLS was achieved.

like image 51
Arcones Avatar answered Sep 21 '22 17:09

Arcones


You can add the AWS provided certificate to the java's trust store then java will trust requests to AWS service by default.
You will have to find your java cacerts file. Depending on your OS and java version it should be in ..lib/security/cacerts.
I am using OSX and it was in
/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts

Then you cause keytool to import it the default java keystore password is change it:

keytool -import -trustcacerts -keystore /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts -storepass changeit -noprompt -alias aws-rds -file rds-combined-ca-bundle.pem

To check if the certificate was imported you can use:
keytool -list -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/security/cacerts | grep aws

Post back if that worked.

like image 25
Yan Avatar answered Sep 18 '22 17:09

Yan