Securing MongoDB with X.509 Authentication

We look at how to configure transport encryption on a deployed MongoDB replica set.Encrypting intra-node traffic ensures that no one can “sniff” sensitive data on the network.This article will guide you through the process of setting up a MongoDB cluster that will utilise X.509 authentication with self signed certificates. Our cluster will consist of 3 nodes that will be deployed as a replica set.

MongoDB supports x.509 certificate authentication for use with a secure TLS/SSL connection. The x.509 client authentication allows clients to authenticate to servers with certificates rather than with a username and password. Basic RGB

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.

For production use, your MongoDB deployment should use valid certificates generated and signed by a single certificate authority. You or your organization can generate and maintain an independent certificate authority, or use certificates generated by a third-party TLS/SSL vendor.

x509

We have an existing setup of MongoDB 4.0 replica set running on three Linux Virtual machines.

Enable Role-Based Access Control

In order for the encryption to be used in our replica set, we need first to activate Role-Based Access Control (RBAC).

Prior to activating RBAC, let’s create an administrative user. We’ll connect to the PRIMARY member and do the following:

server1:PRIMARY> use admin
switched to db admin
server1:PRIMARY> db.createUser({user: 'admin', pwd: 'XXXXXX', roles:['root']})
Successfully added user: { "user" : "admin", "roles" : [ "root" ] }

Let’s activate the RBAC in the configuration file /etc/mongod.conf on each node

security:
   authorization: enabled

Restart the mongodb process

sudo service mongod restart

Now to connect to MongoDB we issue the following command:

mongo -u admin -p XXXXXX --authenticationDatabase "admin"

Certificates

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

MongoDB supports X.509 certificate authentication for use with a secure TLS/SSL connection. The members can use X.509 certificates to verify their membership of the replica set.

An X.509 certificate needs to be generated for each of our nodes. You will act as the CA so we will sign them ourselves. To do this we firstly create a private key, issue a CA certificate and thereafter issue 3 more certificates for each MongoDB node.

To proceed with certificate generation we need to have openssl installed on our system and certificates need to satisfy these requirements:

  • any certificate needs to be signed by the same CA
  • the common name (CN) required during the certificate creation must correspond to the hostname of the host
  • any other field requested in the certificate creation should be a non-empty value and, hopefully, should reflect our organization details
  • it is also very important that all the fields, except the CN, should match those from the certificates for the other cluster members

On Server1 generate a new private key using openssl

openssl genrsa -out mongoCA.key -aes256 8192

We have created a new 8192 bit private key and saved it in the file mongoCA.key. You will be asked for a passphrase. Go ahead and create a secure passphrase for an additional level of security.

Sign a new CA certificate

Next, create your CA certificate. The details of this certificate should differ to those we will give to the mongo certificates. Fill out Company Name ,Address and details specified.

openssl req -x509 -new -extensions v3_ca -key mongoCA.key -days 365 -out mongoCA.crt
root@server1:~# openssl req -x509 -new -extensions v3_ca -key mongoCA.key -days 365 -out mongoCA.crt
Enter pass phrase for mongoCA.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:IN
State or Province Name (full name) [Some-State]:Karnataka
Locality Name (eg, city) []:Bangalore
Organization Name (eg, company) [Internet Widgits Pty Ltd]:dinfratechsource
Organizational Unit Name (eg, section) []:Technologies
Common Name (e.g. server FQDN or YOUR name) []:server1
Email Address []:dptsource@gmail.com

Issue self-signed certificates for all the nodes

For each node, we need to generate a certificate request and sign it using the CA certificate we created in the previous step.

For the first node issue the following commands.

openssl req -new -nodes -newkey rsa:4096 -keyout server1.key -out server1.csr
openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in server1.csr -out server1.crt
cat server1.key server1.crt > server1.pem

For the Second node :

openssl req -new -nodes -newkey rsa:4096 -keyout server2.key  -out server2.csr
openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in server2.csr -out server2.crt
cat server2.key server2.crt > server2.pem

For the third node:

openssl req -new -nodes -newkey rsa:4096 -keyout server3.key -out server3.csr
openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in server3.csr -out server3.crt
cat server3.key server3.crt > server3.pem

Note : To do this we can create a bash script to automate this creation process and ensure there are no errors. All 3 certificate details have to be identical, apart from the host name. This is the reason hard coding an automated script is a more preferred and quicker way of generating our certificates.

#!/bin/bash
if [ "$1" = "" ]; then
echo 'Please enter your hostname (CN):'
exit 1
fi
HOST_NAME="$1"
SUBJECT="/C=GB/ST=London/L=London/O=OrganisationName/OU=OnlineServices/CN=$HOST_NAME"
openssl req -new -nodes -newkey rsa:4096 -subj "$SUBJECT" -keyout $HOST_NAME.key -out $HOST_NAME.csr
openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in $HOST_NAME.csr -out $HOST_NAME.crt
rm $HOST_NAME.csr
cat $HOST_NAME.key $HOST_NAME.crt > $HOST_NAME.pem
rm $HOST_NAME.key
rm $HOST_NAME.crt

Run the above script on all the three nodes

We could execute all of the commands in the previous step on the same host, but now we need to copy the generated files to the proper nodes:

  • Copy to each node the CA certifcate file: mongoCA.crt
  • Copy each self signed certifcate <hostname>.pem into the relative member
  • Create on each member a directory that only the MongoDB user can read, and copy both files there
sudo mkdir -p /etc/mongodb/ssl
sudo chmod 700 /etc/mongodb/ssl
sudo chown -R mongod:mongod /etc/mongodb
sudo cp server1.pem /etc/mongodb/ssl
sudo cp mongoCA.crt /etc/mongodb/ssl

Repeat this process for all your nodes. Move server2 and server3 as well as mongoCA.crt on to node 2 and node 3 in the same directory.

Configure mongod

Change the configuration file /etc/mongod.conf on each host adding the following rows:

net:
   port: 27017
   ssl:
      mode: requireSSL
      PEMKeyFile: /etc/mongodb/ssl/server1.pem
      CAFile: /etc/mongodb/ssl/mongoCA.crt
      clusterFile: /etc/mongodb/ssl/server1.pem
   security:
      authorization: enabled
      clusterAuthMode: x509

Restart the daemon

sudo service mongodb restart

For PEMKeyFile and clusterFile we have to use the respective .pem files of that server.Change the configuration file in all the three nodes and restart the daemon.

mode: preferSSL 

Connections between servers use TLS/SSL. For incoming connections, the server accepts both TLS/SSL and non-TLS/non-SSL.

PEMKeyFile:/etc/mongodb/ssl/server3.pem

The .pem file that we created using the private key and certificate of that particular server.

Note: We created unencrypted server’s private key, so we do not have to specify the net.ssl.PEMKeyPassword option. If the private key is encrypted and if we do not specify net.ssl.PEMKeyPassword option then mongod or mongos will prompt for a passphrase.

CAFile: /etc/mongodb/ssl/mongo-CA-cert.crt

This option requires a .pem file containing root certificate chain from the Certificate Authority. In our case we have only one certificate of CA, so here the path of the .crt file is specified.

clusterFile: /etc/mongodb/ssl/server3.pem

This option specifies the .pem file that contains the x.509 certificate-key file for membership authentication. If we skip this option then the cluster uses the .pem file specified in the PEMKeyFile setting. In our case this file is same, so we may skip this option as our .pem file is same as the one we specified in PEMKeyFile setting.

clusterAuthMode: x509 

The authentication mode used for cluster authentication.

After starting the mongod if we check the logs, we can see lines as shown below:

2018-12-15T05:10:19.124+0530 I ACCESS [conn8] authenticate db: $external { authenticate: 1, mechanism: "MONGODB-X509", user: "emailAddress=dptsource@gmail.com,CN=server2,OU=Technologies,O=dinfratechsource,L=Bangalore,ST=Karnataka,C=IN" }
2018-12-15T05:10:20.245+0530 I ACCESS [conn9] authenticate db: $external { authenticate: 1, mechanism: "MONGODB-X509", user: "emailAddress=dptsource@gmail.com,CN=server3,OU=Technologies,O=dinfratechsource,L=Bangalore,ST=Karnataka,C=IN" }

Issue the following command to connect on node server1:

sudo mongo --authenticationDatabase 'admin' --ssl --sslCAFile '/etc/mongodb/ssl/mongoCA.crt' --sslPEMKeyFile '/etc/mongodb/ssl/server1.pem' -u 'admin' -p 'XXXXXXX' --host 'server1'

Enabling client SSL x.509 certificate authentication

Each unique x.509 client certificate corresponds to a single MongoDB user, so we have to create client x.509 certificates for all the users that we need to connect to the database. We can not use one client certificate to authenticate more than one user. First we will create the client certificates and then we will add the corresponding mongodb users.

A single Certificate Authority (CA) must issue the certificates for both the client and the server.

A client x.509 certificate’s subject, which contains the Distinguished Name (DN), must differ from the certificates that we generated for our mongodb servers server2, server3 and server4. The subjects must differ with regards to at least one of the following attributes: Organization (O), the Organizational Unit (OU) or the Domain Component (DC). If we do not change any of these attributes, we will get error (“Cannot create an x.509 user with a subjectname that would be recognized as an internal cluster member.”) when we add user for that client.

For testing we are going to change the Organizational Unit attribute.
For our mongodb server server1, server2 and server3 certificates, we generated CSR with Organizational Unit as Technologies, for client certificate I am going to use Organizational Unit as Technologies- Client.

openssl req -new -nodes -newkey rsa:4096 -keyout rootuser.key -out rootuser.csr
..................................+
writing new private key to 'rootuser.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:IN
State or Province Name (full name) [Some-State]:Karnataka
Locality Name (eg, city) []:Bangalore
Organization Name (eg, company) [Internet Widgits Pty Ltd]:dinfratechsource
Organizational Unit Name (eg, section) []:Technologies-Client
Common Name (e.g. server FQDN or YOUR name) []:root
Email Address []:dptsource@gmail.com

After that using the same CA as we did for our server certificates, we signed the client certificate CSR and generated our client certificate.

openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in rootuser.csr -out rootuser.crt

Then we concatenated the user’s private key and the public certificate and created the .pem file for that user.

cat rootuser.key rootuser.crt > rootuser.pem

Our client certificate is created, we have to add user in MongoDB for this certificate. To authenticate with a client certificate, we have to add a MongoDB user using the value of subject collected from the client certificate.

openssl x509 -in /etc/mongodb/ssl/rootuser.pem -inform PEM -subject -nameopt RFC2253

We will add one user in the dinfra database (Users created on the dinfra database should have credentials stored externally to MongoDB).

s0:PRIMARY> db.getSiblingDB("dinfra").runCommand({
... createUser: "emailAddress=dptsource@gmail.com,CN=root,OU=Technologies-Client,O=dinfratechsource,L=Bangalore,ST=Karnataka,C=IN",
... roles: [{role: "root", db: "admin"}]
... })

Our client certificate is created, corresponding user is created, we are ready to connect to mongodb using SSL certificate.

For that first we have to change the value of ssl mode option from existing preferSSL to requireSSL in all our mongod server config files.

Now the client authentication needs x.509 certificates rather than username and password as we change the ssl mode to requireSSL.

mongo --ssl --sslPEMKeyFile '/etc/mongodb/ssl/rootuser.pem' --sslCAFile '/etc/mongodb/ssl/mongo-CA-cert.crt' --host server1

When mongo shell connects to our mongod using ssl certificate as shown above, only the connection part is completed. To have authenticated, we have to use the db.auth() method in the dinfra database as shown below:

s0:PRIMARY> db.getSiblingDB("dinfra").auth(
... { mechanism: "MONGODB-X509",
... user: "emailAddress=dptsource@gmail.com,CN=root,OU=Technologies-Client,O=dinfratechsource,L=Bangalore,ST=Karnataka,C=IN"
... }
... )

Once we authenticated, we can run our queries and do admin tasks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Powered by WordPress.com.

Up ↑

%d bloggers like this: