
Hi everyone! This is one of the most requested subjects to our support team and I’d like to share the steps as a tutorial blog post. Today, we will set up internal authentication using x.509 certificates as well as enabling TSL/SSL.
If using authentication in MongoDB, there are two ways to configure intra-cluster authentication:
- Using a Key File
- Using x509 certs
Key files are very straight forward; just create a random text file and share it with all the members in the replicaset/sharding. However, this is not the most secure way and for this reason, it is very common to use certificates instead.
It is perfectly possible to have self-signed certificates, but in this blog, we will use easy-rsa to make real certificates signed by one certificate authority. By the documentation, easy-rsa is a CLI utility to build and manage a PKI CA. In laymen’s terms, this means to create a root certificate authority, and request and sign certificates, including sub-CAs and certificate revocation lists (CRL). This project is hosted on GitHub on https://github.com/OpenVPN/easy-rsa and we are going to use release 2.x for this tutorial.
We will use Percona Server for MongoDB v3.6 – which is currently one of the most used versions – but this works for any MongoDB version starting at 3.2. The steps as to how to create a user will be omitted in this blog. We are considering the primary is configured with authentication and the first user was already created.
Steps:
- Download and configure easy-rsa:
yum install git -y mkdir /usr/share/easy-rsa git clone -b release/2.x https://github.com/OpenVPN/easy-rsa.git cp easy-rsa/easy-rsa/2.0/* /usr/share/easy-rsa cd /usr/share/easy-rsa
- Edit the source files with information about your company:
cd /usr/share/easy-rsa nano vars # These are the default values for fields # which will be placed in the certificate. # Don't leave any of these fields blank. export KEY_COUNTRY="US" <your data> export KEY_PROVINCE="NC" <your data> export KEY_CITY="DURHAM" <your data> export KEY_ORG="Percona" <your data> export KEY_EMAIL="me@percona.com" <your data> export KEY_OU="MongoDB" <your data> #You may need to add the following variable: #Bug: https://bugs.launchpad.net/serverguide/+bug/1504676 export KEY_ALTNAMES=""
- Load the variables with the source command:
source ./vars
- Edit the openssl-1.0.0.cnf file commenting the keys right after [ usr_cert ]
#extendedKeyUsage=clientAuth #keyUsage = digitalSignature
More info here on Extended Key Usage - Now everything is prepared to create our CA file. Let’s create the CA and the members’ certificates:
cd /usr/share/easy-rsa # this command will clean all the data in the ./keys folder ./clean-all # It will generate a key for the CA as well as a certificate ./built-ca # It will generate a key for the server as well as a certificate ./built-key <server_name>
- We suggest keeping the default values for the CA and informing the FQN or the hostname in the certificates. (It will be validated by MongoDB.)This is the expected output:
Generating a 2048 bit RSA private key ......................................................................................+++ ............................+++ writing new private key to 'server_name.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) [US]: State or Province Name (full name) [NC]: Locality Name (eg, city) [Durham]: Organization Name (eg, company) [Percona]: Organizational Unit Name (eg, section) [MongoDB]: Common Name (eg, your name or your server's hostname) [server_name]: Name [EasyRSA]: Email Address [percona@percona.com]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: Using configuration from /usr/share/easy-rsa/openssl-1.0.0.cnf Check that the request matches the signature Signature ok ... Certificate is to be certified until Mar 9 11:29:40 2028 GMT (3650 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
- After creating all the certificates, we need to combine the keys and its certificate in order to create the .pem file.
cd keys -rw-r--r-- 1 root root 1,7K Mar 9 09:35 ca.crt -rw------- 1 root root 1,7K Mar 9 09:35 ca.key -rw-r--r-- 1 root root 4,1K Mar 12 08:29 server_name.crt -rw-r--r-- 1 root root 1,1K Mar 12 08:29 server_name.csr -rw------- 1 root root 1,7K Mar 12 08:29 server_name.key # combining .key and .crt into a single file. cat server_name.key server_name.crt > server_name.pem
Repeat this process to all the server keys. - Now that we have the server .pem files prepared we need to edit the mongod.conf, considering the keys were moved to /var/lib/mongodb/
security.clusterAuthMode : x509 security.authorization : enabled net: port: 27017 bindIp: <ip_number> ssl: mode: requireSSL PEMKeyFile: /var/lib/mongodb/server_name.pem CAFile: /var/lib/mongodb/ca.crt
- Once the changes are made, the services must be started and the members should start normally.
- It is now time to configure the clients, as otherwise, no one will be able to log in to this environment. Again we need to edit the openssl-1.0.0.cnf removing the comments. Clients need to have those keys in the certificate.
cd /usr/share/easy-rsa extendedKeyUsage=clientAuth keyUsage = digitalSignature
- After editing the file, create the client file, it is as simple as creating a new key:
cd /usr/share/easy-rsa ./build-key <client_name>
There is a caveat here, the Organization Unit must be different than MongoDB. I recommend calling as a MongoDBClient, and once the files are created repeat the process of linking the client_name.crt and the client_name.key file in a single file and using it to log in to the environment.
./build-key client_name …. Country Name (2 letter code) [US]: State or Province Name (full name) [NC]: Locality Name (eg, city) [DURHAM]: Organization Name (eg, company) [Percona]: Organizational Unit Name (eg, section) [MongoDB]:MongoDBClient Common Name (eg, your name or your server's hostname) [client_name]: cd keys cat client_name.key client_name.crt > client_name.pem
- Connecting to the database is simple; we need to specify the ca file along with the certificate the client is connecting.
Please be aware you’ll need to connect to the server local IP instead of localhost, and you may need to edit the /etc/hosts in order to force the databases and clients to resolve the hostnames.
mongo --ssl --host server_name --sslCAFile /usr/share/easy-rsa/keys/ca.crt \ --sslPEMKeyFile /usr/share/easy-rsa/keys/client_name.pem --port 27017 \ -u <user> -p --authenticationDatabase admin
With these described steps you should be able to enable SSL + member authentication in your environment. Please feel free to give us feedback here or tweet to @AdamoTonete or @Percona on Twitter!