MongoDB Field EncryptionOne of the main topics we have today is surely about security. On a daily routine, this can pass unnoticed, but sooner or later, we have to implement or work on some security guidelines. And today, we are going to discuss one of them, which is Field Encryption

Feature Introduction

Discussing the feature per se, it’s new in version 4.2+ releases only. And MongoDB provides two methods of Field Encryption, they are:

The automatic mode is available only on the Enterprise Edition and Atlas, while the manual method is supported on the Community Edition by the MongoDB drivers and mongo shell as well.

This article will use the Percona Server for MongoDB (PSMDB) running version 4.4 release with authentication enabled and the manual method in this article. As our objective here is to demonstrate the feature, we will use the mongo-shell to run all the operations.

However, for the application encrypting via driver is the most suggested approach. There is a detailed list of supported drivers for field-level encryption in the official documentation:

https://docs.mongodb.com/manual/core/security-client-side-encryption/#field-level-encryption-drivers

How To

   1 – To start using the feature, and illustration purpose, we will use the locally Managed Keyfile as our Key Management Service (KMS). 

It’s important to mention a local keyfile is quick, but lower security, thus not recommended in a production environment as it is stored alongside the database. For production, please consider using one of the following services:

As Key Management Service (KMS), MongoDB also supports:

  • Amazon Web Services KMS
  • Azure Key Vault
  • Google Cloud Platform KMS

Using locally Managed Keyfile, MongoDB requires specifying a file with base64-encoded 96-byte string with no line breaks[1]; Which can be created with the following example:

Please make sure to save the keyfile in a secure location, to avoid losing it. Otherwise, you would not be able to decrypt or read it later.

   2 – Once we have the key file, let’s open a mongo shell session with the database without connecting yet. Using the option –nodb; also use –shell to execute supplied code (in this case the –eval string value) without an automatic exit at the end; This step is necessary as we have to load the key into an object which will become a database connection property latter. In the following example, we are loading our key file into the database variable LOCAL_KEY:

   3 – Next, load the document ClientSideFieldLevelEncryptionOptions using the proper client-side field-level encryption configuration:

   4 – After setting the variable; We can establish an FLE-enabled connection using the above variables via ClientSideFieldLevelEncryptionOptions on Mongo() constructor. This connection is also using normal username+password authentication as you can see in the mongodb://…/ URI string.

   5 – The next step will be to create the internal keyvault object per se; Until this moment, we were setting the variables and adjusting our client connections to proceed. It can be made as follow:

  5.1 – For extra illustration, as the above command does not generate any output; With a different session, we can check the newly created vault structure on the server: 

   6 – With all set and vault structures deployed, let’s add a data encryption key to the database connection’s key vault. If successful, createKey() returns the UUID of the new data encryption key. This UUID which is a BSON Binary it’s our encryption key and will be used to encrypt the fields manually:

   7 – Next, let’s insert a document using the above key to encrypt; Please note we did the above operations in the same mongo-shell, and to encrypt, we are going to use the encrypt() method along with the parameters to hide the SSN: “123-45-6789”.

    7.1 To use the encrypt() function on a field it expects the following 3 arguments: 

  •   encryptionKeyId – This is our generated key.
  •   Value – In this example, we are going to hide the “123-45-6789” value from SSN.
  •   encryptionAlgorithm – And what algorithm are we going to use to encrypt the field, we can choose between Deterministic Encryption[2] or Randomized Encryption[3]

    7.2 – With all set, we can insert the document encrypting the field as follows:

Perfect! At this point, we were able to encrypt the field manually.

So, now you must be thinking –

How can I read that encrypted value?

Let demonstrate in the next section.

Reading an Encrypted Field

At this point, if we connect without passing the encryption configuration, we will not be able to read the information:

1 – To read, the client must load the ClientSideFieldLevelEncryptionOptions configuration into its session; By opening a connection, load the options into the variable, and use the Mongo() constructor to logging, similar as we did before, but at this time, without the requirement of key vault configuration:

(that’s why is important to store the key in a safe place, as its encoding will be used on the read-write encrypt routine)

2 – Into the session, and with the configuration done, we can run a find()  to return the plain document:

Common Questions

When implementing a new feature, we also start thinking about scenarios we would like to understand before implementing it. Here are some questions that you might have after reading this article:

     1. Can a root user be able to read the fields?

    • No, what dictates if a user will be able to read encrypted fields is if the connection is loaded with the used encryption key; Without it, the user won’t be able to read, even if it has root privileges on the database.

    2. What happens if I lose the Key?

    • Deleting or losing the customer master key renders all data encryption keys encrypted with that as permanently unreadable, which in turn causes all values encrypted with those data encryption keys as permanently unreadable.

     3. How does it work in a ReplicaSet or Sharded Cluster?

    • The same behavior noted in the “Reading an Encrypted field” section happens for both configurations; Once inserted a document with an encrypted field, it is replicated throughout the nodes as it is; encrypted. And only a user with the correct key will be able to read it.

     4. Are there any limitations to using the feature?

    • Yes, in the official manual here. It has a comprehensive description of the limitations; We suggest you review the manual as limitations exist on different configurations as Shard Key, Unique Indexes, Collation, Views, and so on. 

And if you have any further questions, please feel free to share them with us in the comment section below.

Conclusion

Even with the restriction to use the Automatic Client-Side Field Level Encryption, the manual method and the feature per se have shown us to be an exciting option, mainly because it strengthens the security by allowing encrypting sensitive fields natively from MongoDB instead of using third-party tools. It is helping to reduce possible breaches a third-party tool can create.

Additionally, if you are looking for a list of security measures to implement to protect the MongoDB installation, you can use the MongoDB Security Checklist, which is a good starting point if you are not following any standard security policy.

References:

Percona Distribution for MongoDB is a freely available MongoDB database alternative, giving you a single solution that combines the best and most important enterprise components from the open source community, designed and tested to work together.

Download Percona Distribution for MongoDB Today!

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments