MongoDB SSL with Self-Signed Certificates in Node.js

ScaleGrid supports SSL configuration for MongoDB and can be easily set up as outlined in an earlier post. 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, we created this post to share a step-by-step workaround plan to the most commonly faced issues 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.

At ScaleGrid, we also provide you with the option of purchasing your own SSL certificates and configuring them on the MongoDB server. Please email support@scalegrid.io to learn more about this opportunity.

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” CA’s it consults if a CA is not specified during the connection creation time. However, since we’re 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 ScaleGrid, 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

  • 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);
    ...
    
  • 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)

  • 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();
     });
    
    
  • 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, it’s 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 example:

  • 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’s 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 certificate versus the client attempting to connect. Thus, most TLS/SSL servers provider a way to turn it off. For example. 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’s 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