MongoDB SSL with self signed certificates in Node.js

Scalegrid supports SSL configuration for MongoDB. Configuring and setting it up is easy  and our earlier post talks all about it. It also discusses the need and pros and cons of MongoDB with TLS/SSL.

Scalegrid currently uses self signed certificates for SSL when creating nodes for a new cluster. Since Node.js applications over the MongoDB Node.js driver or Mongoose are very popular choices on our platform, in this post we discuss a step by step plan to workaround most common issues faced in using MongoDB SSL with self signed certificates in Node.js. This discussion pertains to the MongoDB Node.js version 2.0 and Mongoose version 4.0.3.

Scalegrid also provides you the option of purchasing your own SSL certificates and configuring them on the mongodb server. Please email support@scalegrid.io if you want to take this route.

Adding CA Certificate File

In order to improve the security of your SSL connection you can specify the CA to be used to validate the MongoDB server SSL certificate. Node.js has a default list of well known “root” CAs which it consults if a CA is not specified during connection creation time. However since we are talking about self signed certificates we will have to specify a CA certificate file for verification. You may copy the CA certificate file that was used for self signing into the client machine (For MongoDirector, this is described in our older SSL post) and then use the sslCA option to point to the path of this file, thus enabling server verification as well.

Mongoose:

a. For standalone clusters:

var fs = require('fs');
var mongoose = require('mongoose');
var certFileBuf = fs.readFileSync(<path to CA cert file>);
var mongoUrl = 'mongodb://admin:blahblah@test0.servers.example.com:27017/admin?ssl=true';
var options = {
  server: { sslCA: certFileBuf }
};
mongoose.connect(mongoUrl, options);
...

b. For Replica Set clusters:

var fs = require('fs');
var mongoose = require('mongoose');
var certFileBuf = fs.readFileSync(<path to CA cert file>);
var mongoUrl = 'mongodb://admin:blahblah@test0.servers.example.com:27017,test1.servers.example.com.com:27017/admin?replicaSet=RS-rstestNode-0&ssl=true';
var options = {
  replset: { sslCA: certFileBuf }
}
mongoose.connect(mongoUrl, options);
...

MongoDB native driver (and wrappers around it, like Mongoskin):

a. For standalone clusters:

var certFileBuf = fs.readFileSync(<path to CA cert file>);
var mongoUrl = 'mongodb://admin:blahblah@test0.servers.example.com:27017/admin?ssl=true';
var options = {
  server: { sslCA: certFileBuf}
};
var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

MongoClient.connect(mongoUrl, options, function(err, db) {
   assert.equal(null, err);
   console.log("Connected correctly to server");
   db.close();
 });

b. For Replica Set clusters: the option parameter for replica sets is replSet:

var options = {
  replSet: {
    sslCA: certFileBuf
  }
};
var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

MongoClient.connect(mongoUrl, options, function(err, db) {
   assert.equal(null, err);
   console.log("Connected correctly to server");
   db.close();
 });

Disabling SSL Certificate Verification

You can disable SSL Certificate Verification altogether as well. This is perhaps easiest to do and most certain to work for you, however not the recommended way to go. The MongoDB driver provides server level and replica set level SSL options (sslValidate, sslCA, sslCert, sslKey, sslPass) to configure SSL connections. All the options are described in detail in the documentation. In the case of self signed certificates, the most useful option is the sslValidate. This can be set to false in case of errors like: DEPTH_ZERO_SELF_SIGNED_CERT (self signed certificate). This disables SSL certificate verification but the connection still remains encrypted.

Mongoose lets you pass parameters down the to the driver in it’s connect call. For e.g for Replica Set clusters:

sslValidate needs to be set to false at the ReplicaSet option so:

var mongoose = require('mongoose');
var mongoUrl = 'mongodb://admin:blahblah@test0.servers.example.com:27017,test1.servers.example.com.com:27017/admin?replicaSet=RS-rstestNode-0&ssl=true';
var options = {
  replset: {sslValidate: false}
}
mongoose.connect(mongoUrl, options);
...

For mongodb native driver:

var options = {
replSet: {
    sslValidate: false
  }
};
var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

MongoClient.connect(mongoUrl, options, function(err, db) {
   assert.equal(null, err);
   console.log("Connected correctly to server");
   db.close();
 });

Disabling Hostname Verification

Instead of completely disabling SSL validation, if hostnames are a problem, one can just disable hostname verification.

Hostname verification as a part of the CA certificate verification is currently configurable. It is always recommended that this verification be turned on. However, it might lead to verification failures even if there’s the slightest mismatch in hostname as in the CA cert versus the client attempting to connect. Thus most TLS/SSL servers provider a way to turn it off. For e.g. the Java MongoDB driver 3.0 allows a way to disable hostname verification via the sslInvalidHostNameAllowed property. For MongoDB native driver 2.0 and above a boolean option parameter checkServerIdentity (default true) is provided to disable hostname verification. It is available both at the individual server and replica set levels.


Vaibhaw is a Member of the Technical Staff at ScaleGrid.io (Formerly MongoDirector). You can reach out to him at @_vaibhaw


3 Shares
+1
Tweet
Share
Share3
Pin