Thursday, May 2, 2024
HomeITPalms-on with MongoDB queryable encryption and Node.js

Palms-on with MongoDB queryable encryption and Node.js


MongoDB 6 launched the aptitude to question encrypted information within the database. Information is encrypted for your complete spherical journey: at insert, storage, and question. This quantities to a brand new stage of safety for information, which stays safe whilst it’s used throughout the database. Solely the consumer utility is able to decrypting the information. 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 information retailer and its infrastructure as targets of assault. This quasi-magical functionality does require some additional configuration for purposes. This text will present you how you can arrange a improvement atmosphere 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 information encryption keys (DEKs). These work collectively to safe your information. The DEK is used to encrypt the information 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 susceptible to compromise. If both the CMK or the DEK is misplaced or inaccessible, then the consumer utility can be unable to decrypt the information.

When creating an utility that may use queryable encryption, you need to use a neighborhood 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 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 software, as proven in Itemizing 1.

Itemizing 1. Generate a neighborhood 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 known as the key vault. Queryable encryption holds the CMK-encrypted DEK on this assortment. When making calls towards 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 numerous encryption occurring, however once more, the thought 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 right here. We’ll construct the naked minimal to attempt to preserve sight of the forest by way of 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 known as make-dek.js and insert.js, and add the strains within the package deal.json file like Itemizing 2.

Itemizing 2. makeDEK script

"scripts": {
    "check": "echo "Error: no check specified" && exit 1",
    "makeDEK": "node ./make-dek.js",
    "insert": "node ./insert.js"
}

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

Add dependencies

For the following 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. (Observe that it’s doable to make use of queryable encryption in handbook mode with the MongoDB Neighborhood Server.)

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

Observe that the consumer will need to have the AtlasAdmin position to carry out these steps. You possibly can set the position on the consumer by going to “Database Entry” within the MongoDB console and clicking “Edit” subsequent to your consumer. 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 consumer 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 traditional position 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 under. In an actual app, use an atmosphere variable or config file.

Add shared crypt library

MongoDB helps two kinds of queryable encryption: auto and handbook. Auto is easier, permitting the MongoDB consumer to barter encryption for you. To make use of auto, you want the shared encryption library from MongoDB obtainable right here. Within the drop-down on the proper, choose crypt_shared, specify your working system, and use the newest model, as in Screenshot 1. (You’ll additionally enter an electronic mail deal with to simply accept the license.)

Screenshot 1. Obtain the crypt_shared package deal

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/mongo_crypt_v1.so file. That’s the one we’d like. Observe the trail since you’ll want it later once we set the <MONGO_CRYPT_LIB_PATH> in Itemizing 4 and Itemizing 5.

The make-dek.js code

Now we’re prepared to write down the code for the make-dek.js file. This can 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 coated 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.web/?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: {
         keyVaultNamespace,
         kmsProviders,
         extraOptions,
         encryptedFieldsMap
      }
   });

   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.");
}

run().catch(console.dir);

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 lodges 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 ready on the encryptedFieldsMap.keyId area, 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 area populated. The encryptedFieldsMap tells the consumer which fields are encrypted (with the trail property), on this case secretField. If the queries property is just not set, the sector can 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 a neighborhood 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 now we have the infrastructure in place to insert and question information in secretDB.secretCollection.secretField. That is accomplished 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>:
<ATLAS_PASSWORD>@cluster0.444xyz.mongodb.web/?retryWrites=true&w=majority"

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 all the pieces?"
});
console.log(await unencryptedColl.findOne({ nonsecretField: /universe/ }));
console.log(await encryptedColl.findOne({ "secretField":42 })
);
} lastly {
await unencryptedClient.shut();
await encryptedClient.shut();
}
}

run().catch(console.dir);

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, kind, and queries settings for the key area.

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 information. 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 traditional fields as traditional.

The encrypted consumer is then used to question towards 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.

Observe that secretDB.secretCollection additionally holds metadata in a __safeContent__ area. Ensure 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 improvement effort than unencrypted information, and even regular encrypted information, nevertheless it additionally permits a functionality not achievable by way of every other means: querying information that’s encrypted in isolation from its keys. This delivers a excessive stage of safety for delicate information. For enterprises that require each most information safety and queryability, MongoDB’s queryable encryption could also be vital characteristic.

Copyright © 2022 IDG Communications, Inc.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments