In this third and final post of the series, we look at how to configure transport encryption on a deployed MongoDB replica set. Security vulnerabilities can arise when internal personnel have legitimate access to the private network, but should not have access to the data. Encrypting intra-node traffic ensures that no one can “sniff” sensitive data on the network.
In part 1 we described MongoDB replica sets and how they work.
In part 2 we provided a step-by-step guide to deploy a simple 3-node replica set, including information on replica set configuration.
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). By default, a MongoDB installation permits anyone to connect and see the data, as in the sample deployment we created in part 2. Having RBAC enabled is mandatory for encryption.
RBAC governs access to a MongoDB system. Users are created and assigned privileges to access specific resources, such as databases and collections. Likewise, for carrying out administrative tasks, users need to be created with specific grants. Once activated, every user must authenticate themselves in order to access MongoDB.
Prior to activating RBAC, let’s create an administrative user. We’ll connect to the PRIMARY member and do the following:
1 2 3 4 | rs-test:PRIMARY> use admin switched to db admin rs-test:PRIMARY> db.createUser({user: 'admin', pwd: 'secret', roles:['root']}) Successfully added user: { "user" : "admin", "roles" : [ "root" ] } |
Let’s activate the RBAC in the configuration file /etc/mongod.conf on each node
1 2 | security: authorization: enabled |
and restart the daemon
1 | sudo service mongod restart |
Now to connect to MongoDB we issue the following command:
1 | mongo -u admin -p secret --authenticationDatabase "admin" |
Certificates
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.
In order to use encryption, we need to create certificates on all the nodes and have a certification authority (CA) that signs them. Since having a certification authority can be quite costly, we decide to use self-signed certificates. For our purposes, this solution ensures encryption and has no cost. Using a public CA is not necessary inside a private infrastructure.
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
The following guide describes all the steps to configure internal X.509 certificate-based encryption.
1 – Connect to one of the hosts and generate a new private key using openssl
1 | openssl genrsa -out mongoCA.key -aes256 8192 |
We have created a new 8192 bit private key and saved it in the file mongoCA.key
Remember to enter a strong passphrase when requested.
2 – Sign a new CA certificate
Now we are going to create our “fake” local certification authority that we’ll use later to sign each node certificate.
During certificate creation, some fields must be filled out. We could choose these randomly but they should correspond to our organization’s details.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | root@psmdb1:~# 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]:US State or Province Name (full name) [Some-State]:California Locality Name (eg, city) []:San Francisco Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Ltd Organizational Unit Name (eg, section) []:DBA Common Name (e.g. server FQDN or YOUR name) []:psmdb Email Address []:corrado@mycompany.com |
3 – 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.
Remember: fill out all the fields requested the same for each host, but remember to fill out a different common name (CN) that must correspond to the hostname.
For the first node issue the following commands.
1 2 3 4 5 | openssl req -new -nodes -newkey rsa:4096 -keyout psmdb1.key -out psmdb1.csr openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in psmdb1.csr -out psmdb1.crt cat psmdb1.key psmdb1.crt > psmdb1.pem |
for the second node
1 2 3 4 5 | openssl req -new -nodes -newkey rsa:4096 -keyout psmdb2.key -out psmdb2.csr openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in psmdb2.csr -out psmdb2.crt cat psmdb2.key psmdb2.crt > psmdb2.pem |
and for the third node
1 2 3 4 5 | openssl req -new -nodes -newkey rsa:4096 -keyout psmdb3.key -out psmdb3.csr openssl x509 -CA mongoCA.crt -CAkey mongoCA.key -CAcreateserial -req -days 365 -in psmdb3.csr -out psmdb3.crt cat psmdb3.key psmdb3.crt > psmdb3.pem |
4 – Place the files
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
1 2 3 4 5 | sudo mkdir -p /etc/mongodb/ssl sudo chmod 700 /etc/mongodb/ssl sudo chown -R mongod:mongod /etc/mongodb sudo cp psmdb1.pem /etc/mongodb/ssl sudo cp mongoCA.crt /etc/mongodb/ssl |
Do the same on each host.
5 – Configure mongod
Finally, we need to instruct mongod about the certificates to enable the encryption.
Change the configuration file /etc/mongod.conf on each host adding the following rows:
1 2 3 4 5 6 7 8 9 10 | net: port: 27017 ssl: mode: requireSSL PEMKeyFile: /etc/mongodb/ssl/psmdb1.pem CAFile: /etc/mongodb/ssl/mongoCA.crt clusterFile: /etc/mongodb/ssl/psmdb1.pem security: authorization: enabled clusterAuthMode: x509 |
Restart the daemon
1 | sudo service mongodb restart |
Make sure to put the proper file names on each host (psmdb2.pem on psmdb2 host and so on)
Now, as long as we have made no mistakes, we have a properly configured replica set that is using encrypted connections.
Issue the following command to connect on node psmdb1:
1 2 3 | mongo admin --ssl --sslCAFile /etc/mongodb/ssl/mongoCA.crt --sslPEMKeyFile /etc/mongodb/ssl/psmdb1.pem -u admin -p secret --host psmdb1 |