MongoDB is a document-oriented database that is free and open-source. It is classified as a NoSQL database because it does not rely on a traditional table-based relational database structure. Instead, it uses JSON-like documents with dynamic schemas. Unlike relational databases, MongoDB does not require a predefined schema before you add data to a database. You can alter the schema at any time and as often as is necessary without having to setup a new database with an updated schema.
In this post, we will first use the MongoDB Repository to install the latest version of MongoDB. Then we’ll enable authentication to secure it on the local system. Finally, we’ll show how to more securely allow remote connections if they’re needed.
Before moving forwards, make sure to set up the Server configured with a non-root sudo user and a firewall.
Set Up the Server
Add the MongoDB Repository
MongoDB is already included in Ubuntu package repositories, but the official MongoDB repository provides the most up-to-date version and is the recommended way of installing the software. In this step, we will add this official repository to our server.
Ubuntu ensures the authenticity of software packages by verifying that they are signed with GPG keys, so we first have to import the key for the official MongoDB repository.
1 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 \ |
The following output confirms that we’ve successfully imported the key:
1 | # Output |
Next, we’ll add MongoDB repository details so apt will know where to download the packages. Issue the following command to create a list file for MongoDB.
1 | echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 \ |
Finally, we’ll update the packages list.
1 | sudo apt-get update |
Now we’re ready to install MongoDB.
Install MongoDB
We’ll install the mongodb-org
meta-package, which includes the daemon, configuration and init scripts, shell, and management tools on the server.
1 | sudo apt-get install mongodb-org |
Press enter or type Y to proceed when prompted. Once the installation is complete, we’ll start the Mongo daemon:
1 | sudo systemctl start mongod |
Since systemctl doesn’t provide output, we’ll check the status to verify that the service has started properly.
1 | sudo systemctl status mongod |
Now that we’ve manually started the daemon and verified that it’s running, we’ll ensure that it restarts automatically at boot:
1 | sudo systemctl enable mongod |
The following output confirms that the command was successful:
1 | Created symlink from /etc/systemd/system/multi-user.target.wants/mongod.service |
Next, we’ll take essential steps to secure our databases.
Secure MongoDB
Earlier versions of MongoDB were vulnerable to automated exploits because by default no authentication was required to interact with the database. Any user could create and destroy databases, as well as read from and write to their contents by default. This was compounded because those earlier versions also configured the MongoDB daemon to listen on all interfaces by default, which meant that automated scripts could detect MongoDB instances that weren’t protected by a firewall and, if authentication hadn’t been enabled, gain complete access to MongoDB.
The situation has been mitigated in the 3.x release as well as earlier versions provided by some package managers because the daemon is now bound to 127.0.0.1 so it will only accept connections on the Unix socket. It is not automatically open to the Internet.
However, authentication is still disabled by default, so any users on the local system have complete access to the databases. To secure this we’ll create an administrative user, enable authentication and test.
Add an Admin
To add our user, we’ll connect to the Mongo shell:
1 | mongo |
The output when we use the Mongo shell warns us that access control is not enabled for the database and that read/write access to data and configuration is unrestricted.
1 | # Output |
We’re free to choose the name for the administrative user since the privilege level comes from the assignment of the role userAdminAnyDatabas
e. The database, admin designates where the credentials are stored. You can learn more about authentication in the MongoDB Security Authentication section.
Set the username of your choice and be sure to pick your own secure password and substitute them in the command below:
1 | use admin |
When we issue the db.createUser
command, the shell will prepend three dots before each line until the command is complete. After that, we should receive feedback like the following when the user has been added.
1 | > use admin |
At this point, our user will be allowed to enter credentials, but they will not be required to do so until we enable authentication and restart the MongoDB daemon.
Enable Authentication
Authentication is enabled in the mongod.conf
file. Once we enable it and restart mongod, users still will be able to connect to Mongo without authenticating, but they will be required to provide a username and password before they can interact.
Let’s open the configuration file:
1 | sudo vim /etc/mongod.conf |
In the #security section, we’ll remove the hash in front of security to enable the stanza. Then we’ll add the authorization setting. When we’re done, the lines should look like the excerpt below:
1 | mongodb.conf |
Note that the “security” line has no spaces at the beginning, and the “authorization” line must be indented with two spaces
Once we’ve saved and exited the file, we’ll restart the daemon:
1 | sudo systemctl restart mongod |
If we’ve made an error in the configuration, the daemon won’t start. Since systemctl doesn’t provide output, we’ll use its status option to be sure that it did:.
1 | sudo systemctl status mongod |
If we see Active: active (running) in the output and it ends with something like the text below, we can be sure the restart command was successful:
1 | Apr 25 19:15:42 MongoHost systemd[1]: Started High-performance, schema-free document-oriented database. |
Having verified the daemon is up, let’s test authentication.
Restrict Unauthed Users
First, let’s connect without credentials to verify that our actions are restricted:
1 | mongo |
Now that we’ve enabled authentication, all of the earlier warnings are resolved.
1 | MongoDB shell version v3.4.2 |
We’re connected to the test database. We’ll test that our access is restricted with the show dbs command:
1 | show dbs |
1 | 2017-02-21T19:20:42.919+0000 E QUERY [thread1] Error: listDatabases failed:{ |
We wouldn’t be able to create users or similarily privileged tasks without authenticating. Next, we’ll make sure our Administrative user does have access.
Verify Admin’s Access
We’ll connect as our administrator with the -u option to supply a username and -p to be prompted for a password. We will also need to supply the database where we stored the user’s authentication credentials with the –authenticationDatabase option.
1 | mongo -u Merikanto -p --authenticationDatabase admin |
We’ll be prompted for the password, so supply it. Once we enter the correct password, we’ll be dropped into the shell, where we can issue the show dbs command:
1 | MongoDB shell version v3.4.2 |
Rather than being denied access, we should see the available databases:
1 | show dbs |
1 | admin 0.000GB |
See the MongoDB documentation to learn more about Authentication, Role-Based Access Control, and Users and Roles.
Configuring Remote Access
Before we start working with an installation that allows remote connections, ideally we’ll have MongoDB behind an external firewall, protected by a virtual private network (VPN), or restricted through a bastion host. As we work toward that, however, we can take the somewhat less-complicated step of enabling a firewall on the database server and restricting access to the specific host or hosts that need it.
Enable UFW
In the Initial Server Setup with Ubuntu 16.04 prerequisite, we enabled UFW and allowed only SSH connections. Before we open a port for our client machine, let’s verify UFW’s status:
1 | sudo ufw status |
Note: If the output indicates that the firewall is inactive, activate it with:
sudo ufw enable
Once it’s enabled, rerunning the status command, sudo ufw status will show the rules. If necessary, be sure to allow SSH.
sudo ufw allow OpenSSH
Unless we made changes to the prerequisites, the output should show that only OpenSSH is allowed:
1 | Status: active |
Next, we’ll allow access to the default MongoDB port, 27017, but restrict that access to a specific host. If you’ve changed the default port, be sure to update it in the command below.
1 | sudo ufw allow from client_ip_address to any port 27017 |
Re-run this command using the IP address for each additional client that needs access. To double-check the rule, we’ll run ufw status again:
1 | sudo ufw status |
1 | To Action From |
Note: If you’re new to UFW, you can learn more in the guide, UFW Essentials: Common Firewall Rules and Commands.
With this firewall rule in place, we’re ready to configure MongoDB to listen on its public interface.
Configure a Public bindIP
To allow remote connections, we will add our host’s publically-routable IP address to the mongod.conf file.
1 | sudo vim /etc/mongod.conf |
In the net stanza, add the MongoHost’s IP to the bindIp line:
1 | . . . |
We’ll save and exit the file, then restart the daemon:
1 | sudo systemctl restart mongod |
As we did earlier, we’ll confirm restart was successful:
1 | sudo systemctl status mongod |
The output should contain Active: active (running), and we can proceed to our final test. Mongo is now listening on its default port.
Test the Remote Connection
We’ll test that Mongo is listening on its public interface by adding the –host flag with the IP address from the mongodb.conf file.
1 | mongo -u Merikanto -p --authenticationDatabase admin --host IP_address_of_MongoHost |
1 | MongoDB shell version v3.4.2 |
Reaching the prompt confirms that the daemon is listening on its public IP. At this point, any transaction between a remote connection and the MongoDB host is unencrypted so the next step, before testing the firewall, should be to secure those transations. For help with this, see MongoDB’s Security documentation on Transport Encryption.