MongoDB Security vs. Five ‘Bad Guys’

MongoDB SecurityMost any commercially mature DBMS provides the following five ways to secure the data you keep inside it:

  • Authentication of user connections (== Identity)
  • Authorization (== DB command permissions) (a.k.a. Role-based access control)
  • Network Encryption (a.k.a. Transport encryption)
  • Storage Encryption (a.k.a. Encryption-at-rest)
  • Auditing (MongoDB Enterprise or Percona Server for MongoDB only)

MongoDB is no exception. All of these have been present for quite a while, although infamously the first versions set “–auth” off by default and this is still in effect. (See more in the “Auth – Still disabled by default” section later.)

This article is an overview of all, plus some important clarification to sort out Authentication and Authorization. Network and storage encryption and Auditing will be expanded on in other articles.

MongoDB Security: The bad guy line-up

So what exactly do the five security subsystems do? Where does the responsibility and purpose of one stop, and others, start?

I think the easiest way to explain it is to highlight the ‘bad guy’ each one repels.

Bad guy
Authentication An unknown person, whom you didn’t realize had network access to the database server, who just ‘walks in’ and looks at, copies, or damages the database data.
a.k.a. Access control
A user or application that reads or alters or deletes data other than what they were supposed to.
This ‘bad guy’ is usually a colleague who does it by accident so it’s mostly for safety rather than security, but it also prevents malicious cases too.
Network Encryption Someone who takes a copy of the data being transferred over a network link somewhere between server A and server B.
Storage Encryption Someone who breaks into your datacenter and steals your server’s hard disk so they can read the data files on it.
In practice, they would probably steal the file data over the network or get the disk in a second-hand hardware sale, but the concept is still someone who obtains a copy of the underlying database files.
Auditing A privileged database user who knows how to cover up their tracks after altering database data.
An important caveat – all bets are off if a unix account with the privilege to overwrite the audit log is controlled by db-abusing adversary.

Authentication and authorization must be activated in unison, and auditing requires authentication as a prerequisite, but otherwise, they can be used independently of each other and there is little if any entanglement of code between one the subsystems above and another.

Apart from the caveats of the paragraph above, if you believe that certain bad guys are not a problem for you then you don’t have to use the relevant section.

Which ones should I use, must I use?

Excluding those who are building a public sandpit or honey-trap, no-one can say the “Authentication” bad guy or the “Authorization” bad guy would be an acceptable visitor to their database. So you should at least be using Authorization and Authentication.

Network encryption is almost a no-brainer for me too, but I assume insecure networks as a matter of course. If your MongoDB cluster and all its clients are, for example, inside a virtual private network that you believe has no firewall holes and no privilege escalation risk from other apps then no, you don’t need network encryption.

But if you are a network security expert who is good enough to guarantee your VPN is risk-free, I assume you’re also skilled at TLS/SSL certificate generation. In this case, you will find that setting up TLS/SSL in MongoDB is pretty easy, so why not do it too?

Storage encryption (a.k.a. encryption-at-rest) and Auditing are only high value when certain other risks are eliminated (e.g. unix root access can’t be gained by an attacker on the servers running the live mongod nodes). Storage encryption has a slight performance cost. If Auditing is used suitably, there is not much performance cost, but beware that performance will quickly choke if audit filters are made too broad.

Having said that, it is worth repeating that these last two are high value to some users. If you know you are one of those, please refer to our later articles on them.

Where in the config?

Although it’s all security, it isn’t configured all in the same place.

Authentication security.authorization, (and/or …keyfile or …clusterAuthMode which imply/force it too).
security.sasl and security.ldap are sub-sections for those optional authentication methods.
Authorization (Enabled simultaneously with “Authentication” above.)
Users and roles are not in config files – they are stored within the db itself. Typically in the admin db’s system.users and system.roles collections).
Network encryption net.ssl N.b. not inside the security.* section of the config file.
Storage encryption security.enableEncryption is disk encryption
Auditing auditLog section of the config file, especially the auditLog.filter option.

The above config pointers are just the root positions; in total there are dozens of different settings underneath them.

Authentication and Authorization

Question: “These Authxxxx and Authyyyy words … the same thing right?”

The Answer: 1) No, 2) Yes. 3) Yes, 4) No.

  1. No: Authentication and authorization are not the same things because they are two parts of the software that do different things

Authentication  == User Identity, by means of credential checking.

Authorization == Assigning and enforcing DB object and DB command permissions.

  1. Yes: Authentication and authorization are kind of a single unit because enabling Authentication automatically enables Authorization too.

I assume it was made like this because this matches user expectations from other older databases, and besides, why authenticate if you don’t want to stop unknown users for accessing or changing data? Authorization is enabled in unison with authentication, so connections from unknown users will have no privilege to do anything with database data.

Authorization requires the user name (verified by Authentication) to know which privileges apply to a connection’s requests. So it can’t be enabled independently to the other either.

  1. Yes: Authentication and authorization are sort of the same thing in unfortunate, legacy naming of configuration options

The commandline argument for enabling authentication (which forces authorization to be on too) is simply “–auth”. Even worse, the configuration file option name for the same thing authentication is security.authorization rather than security.authentication. When you use it, though, the first thing that is being enabled is Authentication, and Authorization is only enabled as an after-effect.

  1. No: There is one exception to the ‘Authentication and authorization on together’ rule: during initial setup Authentication is disabled for localhost connections. This is brief though – you get one opportunity to create the first user, then the exception privilege is dropped.

Another exception is when 3.4+ replica set or cluster uses security.transitionToAuth, but its point is obvious and I won’t expand on it here.

Auth – Still disabled by default

MongoDB’s first versions set “–auth” off by default. This has been widely regarded as a bad move.

You might think that by now (mid-2019, v4.0) it would be on by default – but you’d be wrong. Blank configuration still equates to authorization being off, albeit with startup warnings (on and off again in v3.2, on again v3.4) and various exposure reductions such as localhost becoming the only default-bound network device in v3.6.

Feeling nervous about your MongoDB instances now? If the mongod config files do not have security.authorization set to “enabled”, nor include security.keyfile or a security.clusterAuthMode settings which force it on, then you are not using authentication. You can try this quick mongo shell one-liner (with no user credential arguments set) to double-check if you have authentication and authorization enabled or not. 

mongo --host <target_host>:<port> --quiet --eval 'db.adminCommand({listDatabases: 1})'

The response you want to see is an “unauthorized” error. If you get a list of the database names on the other hand, sorry, you have a naked MongoDB deployment.

Note: Stick with the “listDatabases” example above for simplicity. There are some commands such as ismaster that don’t require authorization at any time. If you use those, you aren’t proving or disproving anything about auth mode.

External Authentication

As most people intuitively expect, this is about allowing users to be authenticated in an external service. As one exception it can’t be used for the internal mongodb __system user, but using it for any real human user or client application service account is perfectly suitable. In concrete terms, the external auth service will be a Kerberos KDC, or an ActiveDirectory or OpenLDAP server. 

Using external authentication doesn’t prevent you from having ordinary MongoDB user accounts at the same time. A common situation is that one DBA user for setup and maintenance reasons was created in the normal way (i.e. with db.createUser(…) in the “admin” db) but otherwise every other account is managed centrally in Kerberos or LDAP.

Internal Authentication

Confusingly MongoDB “internal authentication” doesn’t mean the opposite of the external authentication discussed just above.

It would have been better named ‘peer mongodb node authentication as the __system user’. A mongod node running with authentication enabled won’t trust that any TCP peer is another mongod or mongos node just because it talks like one. Rather it requires that the peer authenticates by proof of a shared secret.

Keyfile Internal Authentication (Default)

In the basic case, the shared secret is the keyfile saved in an identical file distributed to each mongod and mongos node in the cluster. “Key” suggests an asymmetric encryption key but in reality, it is just a password even if you generated it from /dev/random, etc. per the documentation’s advice.

Once the password is used successfully, a mongod node will permit commands coming from the authenticated peer to run as the “__system” superuser.

Unfunny fact: if someone has a copy of the keyfile they can simply strip control and non-printing chars from the key file to make the password string that will let them connect as the “__system” user.

mongo --authenticationDatabase local -u __system -p "$(tr -d '\011-\015\040' < /path/to/keyfile)"

Don’t panic if you try this right now as the mongod (or root) user on one of your MongoDB servers and it succeeds. These unix users already have the permissions to disable security and restart nodes anyway. It is not an extra vulnerability if they can do it. There won’t be accidental read-privilege leaking either – mongod will abort on startup if the keyfile is in anything other than 400 (or 600) file permissions mode.

It is, however, a security failure if users who aren’t DBAs (or the server admins with root) are able to read a copy of the keyfile. This can happen by accidentally saving the keyfile in your world-readable source control, or putting them in deployment ‘recipes’. An intermediate-risk increase is when the keyfile is distributed with mongos nodes owned and run as one of the application team’s unix users instead of “mongod” or other DBA team-owned unix user.

X.509 Internal Authentication

The x.509 authentication mechanism does actually use asymmetric public/private keys, unlike the “security.keyfile” above. It must be used in conjunction with TLS/SSL.

It can be used for client connections as well as internal authentication. Information regarding x.509 authentication is spread over two places in the documentation as a result.

The benefit of x.509 is that, compared to the really-just-a-big-password ‘keyfile’ above, it is less likely that one of the keys deployed with mongod and mongos nodes can be abused by an attacker who gets a copy of it. It depends on how strictly the x.509 certificates are set up, however. To be practical if you do not have a dedicated security team that understands x.509 concepts and best practices, and takes on the administrative responsibility for it, you won’t be getting the best points of x.509. These better practices include tightening down which hosts it will work on and being able to revoke and rollover certificates.

Following up

That’s the end of ‘five bad guys’ overview for MongoDB security, with some clarification about Authentication and Authorization thrown in for good measure.

To give them the space they deserve, the following two subsystems will be covered in later articles:

  • Network encryption
  • Storage encryption (a.k.a. disk encryption or encryption-at-rest)

For Auditing please see this earlier Percona blog MongoDB Audit Log.

Quick documentation links

Share this post

Leave a Reply