Countly Documentation

Countly Resources

Here you'll find comprehensive guides to help you start working with Countly as quickly as possible.

Securing MongoDB

How to setup ports and password protect your MongoDB database

Preventing external connections

From the start MongoDB installations were left open to listen to any interface, thus anyone (even from outside) could connect to your database.

Only in recent versions of MongoDB (2.6+) has MongoDB default configuration which sets bindIp to localhost. Excerpt from MongoDB configuration file looks like below;

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1

This means MongoDB will only listen connections from localhost thus it is closed to external or public access.

However, it is not uncommon to see configurations that set bindIp to 0.0.0.0 or comment it out. If bindIp is commented out or set to anywhere, this will mean that unless you have the necessary firewall configuration your MongoDB instance will be publicly accessible.

In order to prevent such a case it is recommended that;

  • Set bindIp properly, as described here
  • If you have to set bindIp to anywhere make sure your firewall configuration blocks external or unwanted connections using a software firewall such as UFW
  • If you are hosting your Countly instance on a cloud provider such as Google Cloud or AWS, set firewall configuration under networking (for Google Cloud) or security groups (for AWS) to prevent outside access to your configured MongoDB port(s)

Adding authentication for your MongoDB database

This is additional and optional layer of security, if you leave your network interfaces open (or only specific ip address, or additionally blocking by firewall), and want to ensure that there is additional security measure.

Adding Authentication for your MongoDB database means that for anyone to connect to your database they will need to provide login and password to actually read and modify the data.

Credentials

For the purpose of this article, we will use value test as login and test123 and password. Please use more secure values in your deployement

Adding root user

Before you enable authentication on MongoDB, it is suggested to create a root user account, so you could manage other users without the need to disable authentication.

# Enter mongo console
mongo

# Switch database to the admin database
use admin

# Add your user with root permission
db.createUser({user:"admin", pwd:"secure_password",roles: [{role:"root", db:"admin"}]})

Adding single user for all Countly Databases

This is easiest and most robust way. You add one user to one database and then use that database to authenticate users on other databases too.

# Enter mongo console
mongo

# Create user for access to any database
use admin
db.createUser({user: "test" , pwd: "test123", roles: [  "readWriteAnyDatabase" ]})

#or

# Add your user with read and write permission to each database separately
use countly
db.createUser({user:"test", pwd:"test123", roles: ["readWrite"]})
use countly_fs
db.createUser({user:"test", pwd:"test123", roles: ["readWrite"]})
use countly_out
db.createUser({user:"test", pwd:"test123", roles: ["readWrite"]})
use countly_drill
db.createUser({user:"test", pwd:"test123", roles: ["readWrite"]})

#or add users with auth source as admin db

# Switch database to the one we will use for authentication
use admin

# Add your user with read and write permission to specific databases
db.createUser({user:"test", pwd:"test123", roles: [{role:"readWrite", db:"countly"},{role:"readWrite", db:"countly_out"},{role:"readWrite", db:"countly_drill"},{role:"readWrite", db:"countly_fs"}]})

Adding multiple users for each Countly Database separately

If you want more control over who does what, you can create separate users for each database.

This step is optional

This step is not needed, if you went with single user for all Countly databases

Connect to your database server (can be the same server Countly is running on) and run

# Enter mongo console
mongo

# Switch database to countly
use countly

# Add your user with read and write permission to this database
db.createUser({user:"test", pwd:"test123",roles: [{role:"readWrite", db:"countly"}]})

# Switch database to countly_fs
use countly_fs

# Add your user with read and write permission to this database
db.createUser({user:"test", pwd:"test123",roles: [{role:"readWrite", db:"countly_fs"}]})

# Switch database to countly_out
use countly_out

# Add your user with read and write permission to this database
db.createUser({user:"test", pwd:"test123",roles: [{role:"readWrite", db:"countly_out"}]})

# If you have Enterprise Edition, do the same for drill database
use countly_drill
db.createUser({user:"test", pwd:"test123",roles: [{role:"readWrite", db:"countly_drill"}]})

Force authentication on single Mongo instances

At this point there are users with credentials created in single database or for each database, depends on what way you chose to go, but MongoDB is not yet forcing authentication, so you can simply access data as you previously did. Next step is to make MongoDB to allow only authenticated access.

Make sure you add users to your databases

Make sure you already have added users to your databases, otherwise you will not be able to access your MongoDB data, unless you switch off forcing authentication.

To force authentication we need to modify MongoDB configuration file, which is usually located at /etc/mongod.conf

Edit it by uncommenting (or adding if they are missing) these lines:

security:
  authorization: enabled

Force authentication on MongoDB replica set

For replica sets, you also need to make sure that communication between instances is secure. For that you need to generate key and copy this key to all mongodb instances.

#generate the key
openssl rand -base64 741 > mongodb.key

#copy it to all mongodb instances and make sure it is in accessible for mongodb user place

#make sure file is owned by same user who owns mongodb process
chown mongodb:mongodb mongodb.key

#and that file has no global or group permissions, only user permissions
chmod 600 mongodb.key

Now modify mongod.conf file to use that key.

security:
  authorization: enabled
  keyFile: /home/mongodb/mongodb.key

Verify authentication working

After you made modifications to mongod.conf file you can restart your mongod process.

systemctl restart mongod
restart mongod

After that you can try connecting to your database and view data

mongo countly
show collections

It should throw out unauthorized error.

Now try connecting using your credentials

#connecting to any database with single admin db user
mongo countly -u test -p test123 --authenticationDatabase admin

#or

#connecting to specific database with its user
mongo countly -u test -p test123

show collections

It should correctly display database collections, which means your authentication is working.

Adding authentication information to Countly

Next step is to setup authentication part on Countly, so it can connect to your database and use it properly.

Firstly let's encrypt the password value before saving it in configuration file.

#should output encrypted value like 3a0330674fa208946f412870fd3a2245[CLY]_true
countly encrypt test123

Now we need to modify 2 configuration files to provide credentials (possibly 3 if you are using separate configuration for drill). So you need to modify:

  • countly/api/config.js
  • countly/frontend/express/config.js
  • countly/plugins/drill/config.js (if your authentication differs for countly_drill then need to create this file, otherwise it will re use the first two configurations)

Modification should look like this for mongodb clause providing user and password:

mongodb: {
        host: "localhost",
        db: "countly",
        port: 27017,
        max_pool_size: 500,
        //providing username
        username: "test",
        //providing encrypted password
        password: "3a0330674fa208946f412870fd3a2245[CLY]_true",
        //mongos: false,
        //only providing this, if you are authenticating through other db
        dbOptions:{
            //name of authentication db in this example is admin
            //only needed if you are using one user for all databases
            authSource: "admin"
        },
        /*
        serverOptions:{
            //server options
            ssl:false
        }
        */
    }