Friday, October 9, 2020

Authenticating to MongoDB using a keyfile

Sometimes, it might be useful to authenticate to MongoDB usign a keyfile. (This requires it to be configured to use a keyfile, mostly for replicaset / sharding internal authentication)

Use cases for this include:

  • Password resets
  • Authenticating on shards from a config server with the same credentials for all shards (e.g. for keyhole, which assumes that that is an option, which results in errors if shards use different passwords)
  • Auto-detected credentials for scripts that need to run (as root) on multiple nodes
  • Automation of operations on the database (e.g. Creating a user using Ansible, without knowing if a user already exists)

Keyfile authentication uses SCRAM (the exact variant depends on the MongoDB version), in the same way that user authentication uses it. (After stripping all whitespace)

Knowing this, I decided to search around for references of "SCRAM-SHA-1" and "keyfile" and then came across info indicating that the username used is "__system". I found hints at this in the last diff on this change in the MongoDB source code.

In order to log in to the local mongodb instance using the keyfile /etc/mongo.keygile (as root that it can be read), the following command can be used:
mongo -u __system -p "$(tr -d '[:space:]' < /etc/mongo.keyfile)" --authenticationDatabase admin

If the connection string is used instead, the password needs the be URL encoded: (This version uses Perl for URL encoding, which might not be available everywhere)
mongo "mongodb://__system:$(tr -d '[:space:]' < /etc/mongo.keyfile | perl -ple 's/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg')@localhost:27017/?authSource=admin"

Note: This will not work on a YAML keyfile, as supported in MongoDB 4.2 or later. (The password for the system user should still be possible to extract using other methods though)

A Percona blog post that also mentions this method