DEV Community

ScaleGrid for ScaleGrid

Posted on

MongoDB SSL with self-signed certificates in C#

When deploying MongoDB in production, it is strongly recommended that you use an SSL-enabled geo-distributed replica-set configuration for maximum security and availability. ScaleGrid provides you two options for setting up SSL.

One option is purchasing your own CA-signed SSL certificates and configuring them on the MongoDB server. If your application connects to the production database over a public network, do reach out to support@scalegrid.io to learn more about this.

But by default, we configure self-signed certificates for SSL when creating nodes for a new cluster. This avoids extra costs, and can be equally secure when correctly configured. But this does mean that your MongoDB driver needs some help to validate the certificate chain.

When handling self-signed certificates, some developers circumvent validation all-together, and seriously compromise security! In this blog post, we show you two methods to securely connect to a MongoDB server configured with self-signed certificates for SSL, using the official C# MongoDB driver. With a few simple steps, you can provide your driver the information it needs to validate the server certificate and keep the connection secure.

Prerequisites

Before you proceed,

  • Make sure your application can connect to your ScaleGrid deployment. Please refer to our MongoDB Connections help doc to review the general steps for connecting your application to a ScaleGrid deployment.
  • You need to have the MongoDB Driver installed. Please refer to the MongoDB Driver docs to review the steps for installing and using the C# MongoDB.Driver.

Note: All the code samples have been tested using MongoDB Driver v2.8.1 along with .NET Framework v4.6.1. However, they should work on any reasonably recent version of .NET Framework and MongoDB Driver.

šŸš§ Remember to...


Modify the file paths and connection URLs in the code samples to your own file paths and URLs. Else the code samples will not work. Please see the bold parts of the code samples for where you need to make changes. For example:
  • <path-to-downloaded-CA-Cert.cer> = C:\Users\User\Folder\caCert.cer
  • <host1> = mongodb://admin:@SG-example.servers.example.com:27017

Method 1: Adding the ScaleGrid Certificate to Windows Trust Store

One of the simplest ways of using self-signed certificates with C# and the .NET Framework is adding the certificate as ā€œTrusted Rootā€ on the Windows Trust Store. Hereā€™s how you can do it:

  1. Download your CA Certificate from the ScaleGrid UI.
  2. Open a PowerShell Prompt - if you wish to add the certificate as trusted-root for all users, you will have to open it in administrative mode.
  3. Execute the following command, or do this using the Microsoft Management Console.:
    • To add only for the current user:
    Import-Certificate -FilePath <path-to-downloaded-CA-Cert.cer> -CertStoreLocation 'Cert:\CurrentUser\Root'
    • To add for everyone:
    Import-Certificate -FilePath <path-to-downloaded-CA-Cert.cer> -CertStoreLocation Cert:\LocalMachine\Root'

Thatā€™s it! Now the self-signed certificate will pass all default validations, and you are ready to create a MongoDB client.

var connURL = "mongodb://admin:<password>@<host1>,<host2>:27017/admin?replicaSet=<ReplicaSetName>&ssl=true";
var client = new MongoClient(connURL);

Method 2: Using Custom Validation Callback

There are two problems with adding the ScaleGrid Certificate to the Windows Trust Store:

  • The settings apply to all programs running on the machine: this can be a security vulnerability.
  • This has to be done once per-machine. If you move your code to a new server, it can suddenly stop working. This leaves the method prone to human error.

Hence, the recommended way to connect using self-signed certificates is to use a custom validation callback that verifies the certificate. Hereā€™s how you can do this:

  1. Download your CA Certificate and save it to a location your application can access (this will typically be its data directory).
  2. From your application, you can read this certificate and match the one you receive from the MongoDB Server.
  3. Alternatively, you can store a cryptographic hash of the certificate. Instead of reading the certificate and matching, you can compute the cryptographic hash over the received certificate and match the results.

Hereā€™s a sample program that has the CA Certificate stored under its bin directory with the name caCert.cer. It simply prints out a list of all databases that exist on the MongoDB Server:


using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace TestMongoDB
{
  class Program
  {
    static void Main(string[] args)
    {
      var connURL = "mongodb:<password>//admin:@<host1>,<host2>:27017/admin?replicaSet=<Replica-Set-Name>&ssl=true";
      var clientSettings = MongoClientSettings.FromUrl(new MongoUrl(connURL));
      clientSettings.UseSsl = true;
      clientSettings.VerifySslCertificate = true;
      clientSettings.SslSettings = new SslSettings();
      clientSettings.SslSettings.ServerCertificateValidationCallback = ValidateServerCertficate;
      var client = new MongoClient(clientSettings);
      using (IAsyncCursor cursor = client.ListDatabases())
      {
        while (cursor.MoveNext())
        {
          foreach (var doc in cursor.Current)
          {
            Console.WriteLine(doc["name"]); // database name
          }
        }
      }
    }

    private static bool ValidateServerCertficate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
      bool certMatch = false; // Assume failure
      switch(sslPolicyErrors)
      {
        case SslPolicyErrors.None:
          Console.WriteLine("No validation errors - accepting certificate");
          certMatch = true;
          break;
        case SslPolicyErrors.RemoteCertificateChainErrors:
          Console.WriteLine("Failed to validate certificate chain. Most likely a self-signed certificate");
          if (chain.ChainElements.Count == 1 && chain.ChainStatus[0].Status == X509ChainStatusFlags.UntrustedRoot) //It is a self-signed certificate, so chain length will be 1.
          {
            X509Certificate savedCert = X509Certificate.CreateFromCertFile("caCert.cer");
            if (savedCert.Equals(cert)) //This verifies that the issuer and serial number matches. You can also use a cryptographic hash, or match the two certificates byte by byte.
            {
              Console.WriteLine("The certificates match");
              certMatch = true;
            }
          }
          break;
        default:
          Console.WriteLine("Name mismatch or remote-cert not available. Rejecting connection");
          break;
      }
      return certMatch;
    }
  }
}

Troubleshooting

If youā€™re having trouble connecting to your SSL-enabled MongoDB deployment, here are a few tips for debugging:

  • First, verify that you can actually connect to the MongoDB server from the server where your application is running. The simplest way to do this is to install mongo shell on the client machine. On Linux, you wouldnā€™t need to install the entire MongoDB server ā€“ you can choose to install just the shell. Once the shell is available, try to use the ā€˜Command Line Syntaxā€™ we provide to attempt to connect to the server.
  • If you are unable to connect via the mongo shell, it means that the client machine is unable to reach the port 27017 of the MongoDB servers. Look at your Security Group, VPC, and/or ScaleGrid firewall settings to ensure that there is connectivity between the client and server machines.
  • If network connectivity is correct, the next thing to check is that you are using versions of MongoDB Driver and .NET Framework that are compatible with the version of your MongoDB server.
  • If you have confirmed that the driver versions are correct, try running a sample C# program in debug mode, similar to the example we provided above. A step-by-step execution would help root cause the problem.
  • If you are still having trouble connecting to your instance, please reach out to us at support@scalegrid.io with detailed results of the above troubleshooting steps and with the exact versions of C# and the Mongo Driver you are using.

If you are new to ScaleGrid and want to give this tutorial a try, sign up for a free 30-day trial to explore the platform and test out connecting MongoDB to your C# application.

Top comments (0)