Secure MongoDB with X.509 Authentication

Sign up for our monthly newsletter

Thanks for subscribing to the newsletter. This is your channel for getting the latest notifications of server and driver releases, details on local MongoDB events, updates on education programs, and the skinny on all things MongoDB.

The MongoDB Engineering Journal

Disclaimer - the following article is intended for a test environment.

Overview

In this tutorial, I will be describing the detailed process of setting up X.509 based authentication, both for cluster inter-member authentication as well as for client authentication, using a local CA (Certificate Authority).

X.509 is one of the multiple authentication mechanisms supported by MongoDB. An X.509 certificate is a digital certificate that uses the widely accepted international X.509 public key infrastructure (PKI) standard to verify that a public key, presented by a client or another member of the cluster, belongs to that said client or member. One of the main benefits compared to conventional password based authentication is it’s more secure in a sense that each machine would need a dedicated key to join the cluster. So stealing an existing key from another machine isn't going to be very helpful for those with an evil agenda.

In MongoDB, we need to understand the distinction between member authentication and client authentication. MongoDB is a distributed database and deployments almost always consist of multiple mongod or mongos processes running on multiple machines. Member authentication refers to the fact that these machines need to verify each other to ensure a node attempting to replicate data is indeed part of the current cluster.

On the other hand, client authentication refers to those MongoDB clients, including mongo shell, export/import tools and MongoDB drivers.
Below is a deployment of standard 3 node replica set and a client.

To enable X.509 certificate based authentication, essentially you will need the following set of certificates:

3x server certificates, one for each MongoDB member

1x client certificate for one client

1x certificate for Root CA and 1x certificate for Signing CA

All the server certificates and client certificates must be signed by same CA.

The bulk part of the work for setting up X.509 authentication would be to create these certificates. The creation of Root CA and Signing CA and the relevant parts of the signing process is a one time effort, while the creation of the server/client certificates are as needed.
For simplicity, I am going to use one machine and I will run multiple mongods on different ports for this exercise. I also put the steps into an executable script if you want to jump to the end. You can download and run the script, and you will have a test setup just like the diagram above in no time. This way you can quickly get things working, boost your confidence, and then come back to study the details.

Preparation

One linux box, I tested on RedHat 7 and Ubuntu 14.04 but it should work with other flavors as well.

Make sure no mongod is already running on 27017 port, or change the port numbers in the shell script

To run the script, go to the directory that contains the script and execute the following:

# chmod +x setup-x509.sh&NewLine; # ./setup-x509.sh

If everything goes smoothly, you should have a 3 nodes replica set running with X.509 as member auth. Then in the current directory, you may connect to the primary node with a newly generated client certificate client1.pem:

Here dn_prefix will be used to construct the full DN name for each of the certificate. ou_member is used to have a different OU than the client certificates. Client certificates uses ou_client in its OU name.

mongodb_server_hosts should list the hostname (FQDN) for all the MongoDB servers while mongodb_client_hosts should list the hostnames for all of the client machines.

For a clean start, let’s kill the running mongods and clean up the working directory (note: don’t use -9 to kill mongod per the manual):

1. Create local root CA

A root CA (Certificate Authority) is at the top of the certificate chain. This is the ultimate source of the trust.
Ideally a third party CA should be used. However in the case of an isolated network (very typical in large enterprise environment), or for testing purpose, we need to use local CA to test the functionality.

Above we first created a key pair root-ca.key with AES256 encryption and 2048 bits strength. Then using openssl req command to generate a self-signed certificate with a validity of 3650 days. One thing to call out here is the argument -x509 which tells openssl to self sign the certificate instead of generating a signing request (as what we will do below). The output is a crt file, a certificate file that contains the public key of the root CA.

2. Create CA config

A CA config file is used to provide some default settings during the certificate signing process, such as the directories to store the certificates etc. You may change the defaults in root-ca.cfg file after it is generated or simply change them within the script.

3. Generate the signing key

Root CA created above is typically not used for actual signing. For signing we need to delegate to so-called Subordinate Authority or Signing CA. In essence, a signing CA is just another certificate that is signed by the root CA.

This script is in a for loop to generate multiple certificates. 3 key steps are involved with each certificate:

Use openssl genrsa command to create a new key pair

Use openssl req command to generate a signing request for the key

Use openssl ca command to sign the key and output a certificate, using the Signing CA we created earlier as the signer

Notice the variable $ou_member. This signifies the difference between server certificates and client certificates. Server and client certificates must differ in the organization part of the Distinguished Names, or in another word and must differ at least in one of the O, OU, or DC values.

5. Generate and Sign client certificates

These certificates are used by clients, such as mongo shell, mongodump, and Java/python/C# drivers to connect to a MongoDB cluster.

This step is essentially the same as step 4 except for the use of $ou_client. This will make the combination of the DC/OU/O for these certificates will be different from the server certs above.

6. Bring up replicaset in non-auth mode

MongoDB does not create a default root/admin user when enabling authentication, and there is no exception with X.509 mode. Instead, the best practice is to create an initial admin user first, then to enable authentication after the admin user has been created.

Now our replica set is up, we need to initialize the replica set and add a user.

7. Initialize replicaset and add initial user

When using X.509 client authentication, each client must have a user created in MongoDB and the user must be granted the necessary permissions. The username must be same as the client's DN (Distinguished Name), which can be obtained by running an openssl command:

8. Restart replicaset in x.509 mode

In real production, you will need to copy each of the certificate/key files to their corresponding hosts before we can start the cluster in X.509 mode. In this tutorial we are doing everything on localhost to keep thing simple.

Start all 3 nodes, note we added the following arguments:

sslMode

clusterAuthMode

sslCAFile: Root CA file we created in step 2, root-ca.key

sslPEMKeyFile: The certificate file for this host/process

sslAllowInvalidHostnames: Only used for testing, allows invalid hostnames

Here the sslCAFile is used to establish a trust chain. As you recall the root-ca.key file contains the certificate of the root CA as well as the signing CA. By providing this file to MongoDB process, it basically tells MongoDB process to trust the certificate contained in this file, as well as all other certificates signed by these certificates contained within.

TJ is a Senior Solutions Architect at MongoDB Inc. TJ is based in Hong Kong and he is responsible for working with customers from a variety of industries to help them designing and architecting MongoDB enabled solutions. TJ is an experienced developer/architect with more than 15 years experience building enterprise grade software. Prior to MongoDB, he worked at FedEx Singapore as Chief Architect. TJ is an active member of open source community, he is the author of open source project Angoose, a lightweight MEAN stack implementation. When TJ is not fiddling with MongoDB, you can find him kitesurfing in the South China Sea.