Fingers-on with MongoDB queryable encryption and Node.js

Deal Score0
Deal Score0

MongoDB 6 launched the aptitude to query encrypted data within the database. Information is encrypted for your complete spherical journey: at insert, storage, and question. This quantities to a brand new degree of safety for information, which stays safe whilst it’s used inside the database. Solely the consumer utility is able to decrypting the info. The database doesn’t maintain the keys to the encrypted information in any respect, but it nonetheless helps querying that information.

Thus MongoDB queryable encryption removes the info retailer and its infrastructure as targets of assault. This quasi-magical functionality does require some additional configuration for purposes. This text will present you methods to arrange a growth surroundings for working with MongoDB queryable encryption in a Node.js utility.

Grasp and information encryption keys

There are two sorts of keys utilized in MongoDB’s queryable encryption: the client grasp key (CMK) and the info encryption keys (DEKs). These work collectively to safe your information. The DEK is used to encrypt the info within the database, whereas the CMK is used to encrypt and decrypt the DEK, including a layer of safety. The CMK is the extra delicate key. If the CMK is compromised, then your information is weak to compromise. If both the CMK or the DEK is misplaced or inaccessible, then the consumer utility shall be unable to decrypt the info.

When growing an utility that may use queryable encryption, you need to use an area file that holds your CMK on the identical server as the applying, as an alternative of a distant key retailer. It’s essential to notice up entrance that in manufacturing, you will need to use a distant key retailer or you’ll undermine the safety of the system.

Generate a CMK

Step one is to generate your CMK. You are able to do this with the openssl command line instrument, as proven in Itemizing 1.

Itemizing 1. Generate an area key

openssl rand 96 > cmk.txt

Create a DEK

We’ll create a easy Node.js program to deal with our CMK, create a DEK, and insert the DEK right into a particular encrypted assortment in MongoDB referred to as the key vault. Queryable encryption holds the CMK-encrypted DEK on this assortment. When making calls in opposition to the encrypted utility information, your consumer utility retrieves the DEK from the important thing vault, decrypts the DEK with the CMK, after which makes use of the decrypted DEK to work together with the database occasion.

That’s a number of encryption happening, however once more, the concept is to maintain the DEK safe by advantage of the CMK.

The MongoDB docs present a extra totally realized model of the app used to create the DEK key vault desk here. We’ll construct the naked minimal to attempt to preserve sight of the forest via the timber.

Create a brand new NPM app by typing npm init. You possibly can settle for all defaults. Now make two new js information referred to as make-dek.js and insert.js, and add the strains within the bundle.json file like Itemizing 2.

Itemizing 2. makeDEK script

"scripts": {
    "take a look at": "echo "Error: no take a look at specified" && exit 1",
    "makeDEK": "node ./make-dek.js",
    "insert": "node ./insert.js"

Now you’ll be able to run makeDEK.js by getting into npm run makeDEK and npm run insert on the command line. (However these instructions received’t do something but.)

Add dependencies

For the subsequent steps we’ll want two packages put in. Enter the instructions in Itemizing 3 to put in them.

Itemizing 3. Add MondoDB dependencies

npm set up mongodb
npm set up mongodb-client-encryption

Arrange MongoDB Atlas

We’ll use Atlas, MongoDB’s managed service, for this tutorial. As of this writing, to create a MongoDB 6 cluster in Atlas, you’ll want a paid-tier devoted cluster. (Be aware that it’s attainable to make use of queryable encryption in guide mode with the MongoDB Neighborhood Server.)

You possibly can create a free Atlas account here. From there it’s straightforward to arrange the cluster (leaving the title as Cluster0) and create a person with password authentication. Simply be sure you choose “Devoted Cluster” if you get that alternative.

Be aware that the person should have the AtlasAdmin function to carry out these steps. You possibly can set the function on the person by going to “Database Entry” within the MongoDB console and clicking “Edit” subsequent to your person. Then within the “Constructed-in Function” drop-down menu, choose AtlasAdmin.

We’ll use the username and password within the subsequent steps to entry the Atlas cluster.

Please word (safety warning):

  • In real-world utilization, don’t use a world permissioned person like AtlasAdmin for accessing the collections after the schema and indexes are created. Create customers with simply sufficient permission to do their work. After creating the schema and indexes, you need to use a standard function to entry the collections (together with the encrypted ones).
  • In an actual utility, you wouldn’t inline your database credentials into the code as we’ll do beneath. In an actual app, use an surroundings variable or config file.

Add shared crypt library

MongoDB helps two kinds of queryable encryption: auto and guide. Auto is less complicated, permitting the MongoDB consumer to barter encryption for you. To make use of auto, you want the shared encryption library from MongoDB accessible here. Within the drop-down on the suitable, choose crypt_shared, specify your working system, and use the newest model, as in Screenshot 1. (You’ll additionally enter an e mail tackle to simply accept the license.)

Screenshot 1. Obtain the crypt_shared bundle

mongodb crypt shared IDG

Now put that file in a handy spot and unzip/untar it. Within the listing created by extraction, you’ll discover a /lib/ file. That’s the one we want. Be aware the trail since you’ll want it later after we set the <MONGO_CRYPT_LIB_PATH> in Itemizing 4 and Itemizing 5.

The make-dek.js code

Now we’re prepared to jot down the code for the make-dek.js file. This shall be a small app that units up the important thing vault assortment and the encrypted assortment itself. These two collections work in tandem to deal with persisting, querying, and retrieving information from the encrypted assortment. (That is lined in additional depth on the MongoDB docs.) The contents of make-dek.js are proven in Itemizing 4.

Itemizing 4. make-dek.js

const { MongoClient, Binary } = require("mongodb");
const { ClientEncryption } = require("mongodb-client-encryption");

const keyVaultNamespace = "encryption.__keyvault";
const secretDB = "secretDB";
const secretCollection = "secretCollection";
const uri = "mongodb+srv://<ATLAS_USERNAME>:<ATLAS_PASSWORD>@cluster0.444xyz.mongodb.internet/?retryWrites=true&w=majority";

async operate run() {
   const keyVaultClient = new MongoClient(uri);
   await keyVaultClient.join();
   const keyVaultDB = keyVaultClient.db("encryption");
   await keyVaultDB.dropDatabase();
   const keyVaultColl = keyVaultDB.assortment("__keyvault");
   await keyVaultColl.createIndex(
      { keyAltNames: 1 },
      { distinctive: true, partialFilterExpression: { keyAltNames: { $exists: true } } }
   const localMasterKey = require("fs").readFileSync("./cmk.txt");
   const kmsProviders = { native: { key: localMasterKey } };
   const clientEnc = new ClientEncryption(keyVaultClient, {
      keyVaultNamespace: keyVaultNamespace,
      kmsProviders: kmsProviders
   const dek = await clientEnc.createDataKey("native", { keyAltNames: ["dek"] });
   const encryptedFieldsMap = {
      ["secretDB.secretCollection"]: {
         fields: [
               keyId: dek,
               path: "secretField",
               bsonType: "int",
               queries: { queryType: "equality" },
   const extraOptions = { cryptSharedLibPath: "<MONGO_CRYPT_LIB_PATH>" };
   const encClient = new MongoClient(uri, {
      autoEncryption: {

   await encClient.join();
   const newEncDB = encClient.db(secretDB);
   await newEncDB.dropDatabase();
   await newEncDB.createCollection(secretCollection);
   await keyVaultClient.shut();
   await encClient.shut();
   console.log("Efficiently created DEK and encrypted assortment.");


Itemizing 4 tells the story of two collections: encryption.__keyvault and secretDB.secretCollection. These two collections are used collectively to assist queryable encryption.

secretDB.secretCollection accommodations the precise enterprise information. The encryption.__keyvault assortment holds the encrypted information encryption keys used on secretDB.secretCollection. There are two MongoClients in use. The encrypted consumer (encClient) is configured with the DEK created by the unencrypted keyVaultClient. The DEK is about on the encryptedFieldsMap.keyId discipline, which is used to configure encClient.

The encryptedFieldsMap holds additional data for the encrypted consumer encClient, which is a regular MongoClient set with the autoEncrypted discipline populated. The encryptedFieldsMap tells the consumer which fields are encrypted (with the trail property), on this case secretField. If the queries property will not be set, the sphere shall be encrypted however not queryable. As of this writing, solely equality is supported as a queryType.

Discover {that a} ClientEncryption object (clientEnc) is used to generate the DEK. The clientEnc object makes use of the keyVaultClient together with the keyVaultNameSpace (encryption.__keyvault) and the kmsProvider.

The kmsProvider is an area key supplier that factors to the random quantity we generated on the command line. Additionally it is utilized by the autoEncryption we set on the encClient consumer. (Reminder: Don’t use native kmsProvider in manufacturing.)

Inserting and querying information

Now we now have the infrastructure in place to insert and question information in secretDB.secretCollection.secretField. That is carried out utilizing the keys in encryption.__keyvault. Itemizing 5 presents a stripped down instance of doing this with two fields, an unencrypted string on nonsecretField and an encrypted int on secretField.

Itemizing 5. Insert and question on encrypted and unencrypted fields

const { MongoClient, Binary } = require("mongodb");

const localMasterKey = require("fs").readFileSync("./cmk.txt");
const kmsProviders = { native: { key: localMasterKey } };
const uri = "mongodb+srv://<ATLAS_USERNAME>:

async operate run() {
const unencryptedClient = new MongoClient(uri);
await unencryptedClient.join();
const keyVaultClient = unencryptedClient.db("encryption").assortment("__keyvault");
const dek = await keyVaultClient.findOne({ "keyAltNames": "dek" });

const encryptedFieldsMap = {
["secretDB.secretCollection"]: {
fields: [
keyId: dek._id,
path: "secretField",
bsonType: "int",
queries: { queryType: "equality" }
const extraOptions = { cryptSharedLibPath: "<MONGO_CRYPT_LIB_PATH>" };
const encryptedClient = new MongoClient(uri, {
autoEncryption: {
keyVaultNamespace: "encryption.__keyvault",
kmsProviders: kmsProviders,
extraOptions: extraOptions,
encryptedFieldsMap: encryptedFieldsMap
await encryptedClient.join();
attempt {
const unencryptedColl = unencryptedClient.db("secretDB").assortment("secretCollection");
const encryptedColl = encryptedClient.db("secretDB").assortment("secretCollection");
await encryptedColl.insertOne({
secretField: 42,
nonsecretField: "What's the secret to life, the universe and every little thing?"
console.log(await unencryptedColl.findOne({ nonsecretField: /universe/ }));
console.log(await encryptedColl.findOne({ "secretField":42 })
} lastly {
await unencryptedClient.shut();
await encryptedClient.shut();


In Itemizing 5 we create two MongoDB shoppers, an unencrypted consumer and an encrypted consumer. With unencryptedClient we entry the keyvault encryption.__keyvault that we created with make-dek.js in Itemizing 4, and we retrieve the DEK we saved there. We then use the DEK to construct the encryptedFieldsMap, which additionally holds the trail, sort, and queries settings for the key discipline.

Subsequent we create the encrypted consumer, specifying the keyvault namespace (encryption.__keyvault), the kmsProvider (which is once more the native file at cmk.txt), the extraOptions pointing to the shared crypt library we downloaded from MongoDB, and the encryptedFieldsMap.

Then we use encryptedClient to insert into the secretDB.secretCollection assortment, with the secretField and nonsecretField set to an int and a string, respectively.

Lastly, we question the info. First we use the unencrypted consumer — this time pointed at secretDB.secretCollection — to question utilizing the nonsecretField and output the end result. The end result will present that the secretField is cipher textual content, whereas the nonsecretField is plaintext. The purpose right here being that the unencrypted consumer can question and use the conventional fields as traditional.

The encrypted consumer is then used to question in opposition to the secretField, and when that result’s output, all fields together with secretField are seen. This demonstrates that encryptedClient has full entry to all fields.

Be aware that secretDB.secretCollection additionally holds metadata in a __safeContent__ discipline. Make sure you don’t alter this or the important thing vault assortment, or issues could not work as anticipated.

Encryption you’ll be able to question

MongoDB queryable encryption requires extra growth effort than unencrypted information, and even regular encrypted information, however it additionally allows a functionality not achievable via another means: querying information that’s encrypted in isolation from its keys. This delivers a excessive degree of safety for delicate information. For enterprises that require each most information safety and queryability, MongoDB’s queryable encryption could also be a must have function.

Copyright © 2022 IDG Communications, Inc.

We will be happy to hear your thoughts

Leave a reply
Enable registration in settings - general