Java driver cannot connect to MongoDB over SSL while MongoDB CLI can

3,163 views
Skip to first unread message

Pinak Pani

unread,
Jan 26, 2016, 10:16:30 PM1/26/16
to mongodb-user
Hi,

I have a MongoDB cluster of 4 machines configured with SSL. Here is how the SSL configuration looks on all the services (Mongod, Mongos, Mongo config and Arbiter):

net:
   ssl
:
      mode
: requireSSL
     
PEMKeyFile: /etc/ssl/pre2.zeldalabs.internal.pem
     
CAFile: /etc/ssl/ca0102-public.pem

I can access Mongos services via MongoDB CLI like this:

mongo --host mon0101.pre2.zeldalabs.internal --sslPEMKeyFile pre2.zeldalabs.internal.pem --sslCAFile ca0102-public.pem --ssl


Here is the Java code:
      import java.io.IOException;
     
import java.io.InputStream;
     
import java.security.KeyManagementException;
     
import java.security.KeyStore;
     
import java.security.KeyStoreException;
     
import java.security.NoSuchAlgorithmException;
     
import java.security.cert.CertificateException;
     
import java.util.Arrays;
     
import java.util.Properties;


     
import javax.net.ssl.SSLContext;
     
import javax.net.ssl.SSLSocketFactory;
     
import javax.net.ssl.TrustManager;
     
import javax.net.ssl.TrustManagerFactory;


     
import com.mongodb.DB;
     
import com.mongodb.DBCollection;
     
import com.mongodb.MongoClient;
     
import com.mongodb.MongoClientOptions;
     
import com.mongodb.ServerAddress;


     
/* -- snip -- */


     
String certLoc = System.getProperty("user.home") + "/certs/mongodb.keystore";
     
System.setProperty("javax.net.ssl.trustStore", certLoc);
     
System.setProperty("javax.net.ssl.keyStore", certLoc);
     
System.setProperty("javax.net.ssl.keyStorePassword", "s3cr3t");
     
System.setProperty("javax.net.ssl.trustStorePassword", "s3cr3t");
     
MongoClientOptions o = MongoClientOptions
           
.builder()
           
.sslEnabled(true)
           
.sslInvalidHostNameAllowed(true)
           
.build();


     
MongoClient m = new MongoClient("mon0101.pre2.zeldalabs.internal:27017", o);


     
@SuppressWarnings("deprecation")
      DB db
= m.getDB( "zeldacluster" );
     
DBCollection c = db.getCollection( "models" );


     
System.out.println( c.findOne() );

The keystore was created using this command:

    keytool -importcert -trustcacerts -file ca0102-public.pem -keystore mongodb.keystore -storepass s3cr3t


It fails with:

Exception in thread "main" com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting for a server that matches ReadPreferenceServerSelector{readPreference=primary}. Client view of cluster state is {type=UNKNOWN, servers=[{address=mon0101.pre2.zeldalabs.internal:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketReadException: Prematurely reached end of stream}}]
  at com
.mongodb.connection.BaseCluster.createTimeoutException(BaseCluster.java:370)
  at com
.mongodb.connection.BaseCluster.selectServer(BaseCluster.java:101)
  at com
.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.<init>(ClusterBinding.java:75)
  at com
.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.<init>(ClusterBinding.java:71)
  at com
.mongodb.binding.ClusterBinding.getReadConnectionSource(ClusterBinding.java:63)
  at com
.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:167)
  at com
.mongodb.operation.FindOperation.execute(FindOperation.java:394)
  at com
.mongodb.operation.FindOperation.execute(FindOperation.java:57)
  at com
.mongodb.Mongo.execute(Mongo.java:760)
  at com
.mongodb.Mongo$2.execute(Mongo.java:747)
  at com
.mongodb.DBCollection.findOne(DBCollection.java:740)
  at com
.mongodb.DBCollection.findOne(DBCollection.java:713)
  at com
.mongodb.DBCollection.findOne(DBCollection.java:660)
  at com
.mongodb.DBCollection.findOne(DBCollection.java:649)
  at we
.com.monitoring.testing.TestShansCode.testMongoSSL1(TestShansCode.java:97)
  at we
.com.monitoring.testing.TestShansCode.main(TestShansCode.java:101)


On Mongos side, I see:

2016-01-27T02:47:15.423+0000 I NETWORK  [mongosMain] connection accepted from 11.11.1.59:54512 #116 (1 connection now open)
2016-01-27T02:47:15.795+0000 E NETWORK  [conn116] no SSL certificate provided by peer; connection rejected
2016-01-27T02:47:15.795+0000 I NETWORK  [conn116] end connection 11.11.1.59:54512 (0 connections now open)
2016-01-27T02:47:16.319+0000 I NETWORK  [mongosMain] connection accepted from 11.11.1.59:54514 #117 (1 connection now open)
2016-01-27T02:47:16.352+0000 E NETWORK  [conn117] no SSL certificate provided by peer; connection rejected
2016-01-27T02:47:16.352+0000 I NETWORK  [conn117] end connection 11.11.1.59:54514 (0 connections now open)

I am not sure what I am doing wrong here; neither do I know where to go from here. I would be grateful if anyone can give me a hint on how to go about it. Thanks for your time.

Wan Bachtiar

unread,
Feb 10, 2016, 12:55:01 AM2/10/16
to mongodb-user

I am not sure what I am doing wrong here; neither do I know where to go from here. I would be grateful if anyone can give me a hint on how to go about it.

Hi Pinak,

This question is not really related to MongoDB itself, but more about Java/Keytool. You may get a wider audience by posting on StackOverflow.

There is a difference between trustStore and keyStore files. A keystore contains private keys, and the certificates with the corresponding public keys. A truststore contains certificates from other parties that you expect to communicate with, or from Certificate Authorities (CA) that you trust to identify other parties. So you would need to have one file for your keystore and another for your truststore.

You have already generated your truststore file i.e. mongodb.keystore. Although maybe you can rename it for clarity, let’s rename it to mongodb.jks for example.

Now you just have to create the client’s keystore file, for example you can create it in a PKCS12 format like so:

openssl pkcs12 -CAfile ca0102-public.pem -export -in pre2.zeldalabs.internal.pem -out mongodb.p12 -password s3cr3t

You can modify in your Java code:

System.setProperty("javax.net.ssl.trustStoreType", "jks");
System.setProperty("javax.net.ssl.trustStore", "/path/certs/mongodb.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "s3cr3t");

System.setProperty("javax.net.ssl.keyStore", "pkcs12")
System.setProperty("javax.net.ssl.keyStore", "/path/certs/mongodb.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "s3cr3t");

For more information on configuring a Java application for SSL, please refer to the JSSE Reference Guide

Kind regards,

Wan.

Reply all
Reply to author
Forward
0 new messages