Severalnines Blog
The automation and management blog for open source databases

Pre-emptive security with audit logging for MongoDB

Art van Scheppingen

Database security is a broad subject that stretches from pre-emptive measurements to keeping unwanted visitors out. Even if you would be able to secure your MongoDB servers fully, you still would like to know if anyone has attempted to break into your system. And if they manage to breach your security and install the MongoDB ransom hack, you would need an audit trail for post-mortems or for taking new preventive measures. An audit log would enable you to keep track of anyone attempting to log in and see what they did in your system.

The MongoDB Enterprise version contains the ability to enable the audit log, but the community version lacks this functionality. Percona created their own audit logging functionality in their MongoDB derived Percona Server for MongoDB. The MongoDB and Percona approaches are different from each other and we will explain how to configure and use both of them.

MongoDB audit logging

The MongoDB audit log is easy to set up: to enable audit logging to a JSON file, simply add the following section to your config file and restart MongoDB:

auditLog:
   destination: file
   format: JSON
   path: /var/lib/mongodb/auditLog.json

MongoDB supports file, console and syslog as destinations. For file formats there are two options: JSON and BSON. In JSON the audit log lines look similar to this:

{ "atype" : "authCheck", "ts" : { "$date" : "2017-02-15T22:20:08.322-0000" }, "local" : { "ip" : "127.0.0.1", "port" : 27017 }, "remote" : { "ip" : "127.0.0.1", "port" : 63357 }, "users" : [], "roles" : [], "param" : { "command" : "update", "ns" : "test.inserttest", "args" : { "update" : "preauth_case", "updates" : [ { "q" : { "createdByUserId" : -2 }, "u" : { "$set" : { "statusCode" : "Update" } }, "multi" : false, "upsert" : false } ], "ordered" : true } }, "result" : 0 }

The configuration above would enable the audit log for each and every action by any user of your system. If you have high concurrency this would dramatically decrease the performance of your MongoDB cluster. Luckily enough, there is the option to filter events that are to be logged.

Filters for the audit logging can be placed on the type of query, the user/role querying or on the collection that is being queried. The documentation on audit logging at MongoDB is very broad and lengthy with many examples. We will give some of the most important examples below.

Authenticating against a specific collection:

    filter: '{ atype: "authenticate", "param.db": "test" }'

Log for multiple audit types:

    filter: '{ atype: { $in [ "update", "delete" ]}, "param.db": "test" }'

Log all authentication checks for insert/updates/deletes on a specific collection:

    filter: '{ atype: "authCheck", "param.ns": "test.orders", "param.command": { $in: [ "find", "insert", "delete", "update", "findandmodify" ] } }'

As you can see the filters can be quite flexible, and you would be able to filter the messages that you require for your audit trail.

Severalnines
 
Become a MongoDB DBA - Bringing MongoDB to Production
Learn about what you need to know to deploy, monitor, manage and scale MongoDB

Percona Server for MongoDB audit logging

The Percona Server for MongoDB audit logging is limited to JSON file. The majority of users will only log to JSON files, but it is unclear if Percona will add other logging facilities in the future.

Depending on the version of Percona Server for MongoDB, your configuration might be different. At the moment of writing, all versions have the following syntax:

audit:
   destination: file
   format: JSON
   path: /var/lib/mongodb/auditLog.json

However this configuration difference has recently been resolved, but still has to be released. After the release it should follow the MongoDB auditLog directive again:

auditLog:
   destination: file
   format: JSON
   path: /var/lib/mongodb/auditLog.json

The format by Percona is slightly different:

{ "atype" : "authenticate", "ts" : { "$date" : { "$numberLong" : "1487206721903" } }, "local" : { "host" : "n3", "port" : 27017 }, "remote" : { "host" : "172.16.140.10", "port" : 50008 }, "users" : [ { "user" : "admin", "db" : "admin" } ], "params" : { "user" : "admin", "db" : "admin", "mechanism" : "SCRAM-SHA-1" }, "result" : 0 }

As opposed to MongoDB logging everything, Percona chose to only log the important commands. Judging from the source of the Percona audit plugin, the following queries are supported: authentication, create/update/delete users, add/update/remove roles, create/drop database/index and most of the important admin commands.

Also the filtering of the Percona Server for MongoDB audit log doesn’t seem to follow the same standard as MongoDB has. It is quite unclear what the exact filter syntax and options are as the Percona documentation is very concise about it.

Enabling the auditlog without filtering would give you more than enough entries in your log file. From here you can narrow the filter down, as it follows the JSON syntax of the log entries.

Making use of the audit log

To make it easier for yourself, it might be the best to feed the audit log into a log analysing framework. An ELK stack is an excellent environment to do your analysis in and it enables you to drill down to more detailed levels quite easily. Using a field mapper would even allow you to do the audit trail inside ELK.

As described in the introduction, we can use the audit log for various security purposes. The most obvious one is when you need it as a reference during a post-mortem. The MongoDB audit log provides a detailed overview of what exactly happened. The Percona audit log contains a little less information, but it should be sufficient for most post-mortems. Using the audit log for post-mortems is great, although we would rather have prevented the issue in the first place.

Another purpose for the audit log is to see trends happening and you could set traps on a certain audit log message. A good example would be to check the rate of (failed) authentication attempts and if this exceeds a certain threshold, act upon it. Depending on the situation, the action taken could differ. One actions could be to automatically block the ip address the requests are coming from, but in another case, you could consult with the user about why the password was forgotten. It really depends on the case and environment you are working in.

Another advanced pre-emptive measurement would be using MongoDB as a honeypot and leveraging the audit log to catch unwanted users. Just expose MongoDB and allow anyone to connect to your MongoDB server. Then use the audit log to detect what users will do if they are allowed to do things beyond their normal powers and block them if necessary. Most humans rather take the easy way than the hard way, so the honeypot could deflect an attack and the hacker will move on to the next target.

Conclusion

Apart from explaining how to set up the audit log for both MongoDB Enterprise and Percona Server for MongoDB, we also explained what you could potentially do with the logged data inside the audit log.

By default ClusterControl will not enable the audit log, but it is relatively easy to enable it cluster wide using our Config Manager. You could also enable it inside the configuration templates, prior to deploying a new cluster.

Happy clustering!