MongoDB’s Field-Level Encryption (FLE) is surprisingly not about encrypting the entire database file at rest, but rather about encrypting specific fields before they even hit the database.
Let’s see it in action. Imagine we want to store customer credit card numbers securely.
// Assuming you have a MongoClient connection already established
const db = client.db("mydatabase");
const collection = db.collection("customers");
// First, set up the encryption schema
const schema = {
bsonType: "object",
properties: {
name: {
bsonType: "string",
},
email: {
bsonType: "string",
},
creditCard: {
encrypt: {
keyId: new BSON.UUID("YOUR_KEY_ID"), // Replace with your actual key ID
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_256",
},
},
},
};
// Apply the schema to the collection
await db.command({
collMod: "customers",
validator: { $jsonSchema: schema },
validationLevel: "strict",
validationAction: "error",
});
// Now, insert a document with sensitive data
const sensitiveData = {
name: "Jane Doe",
email: "jane.doe@example.com",
creditCard: "1234-5678-9012-3456", // This will be encrypted
};
await collection.insertOne(sensitiveData);
// When you query this document, the 'creditCard' field will appear encrypted.
// To decrypt, you need the appropriate KMS key and driver configuration.
The core problem FLE solves is that while database-level encryption protects data if the disk is stolen, it doesn’t protect against a compromised database administrator or an application-level breach. FLE encrypts data at the application layer, meaning only authorized applications with the correct decryption keys can read the sensitive fields.
Internally, FLE uses client-side encryption. The MongoDB driver, configured with your Customer Master Keys (CMKs) managed in a Key Management Service (KMS) like AWS KMS, Azure Key Vault, or Google Cloud KMS, encrypts the specified fields before sending them to the MongoDB server. The server stores the ciphertext. When a query requests an encrypted field, the driver fetches the ciphertext, retrieves the necessary decryption key from the KMS (if authorized), and decrypts the data client-side.
The key levers you control are the schema definition and the KMS configuration. The encrypt object within your schema specifies which fields to encrypt, the keyId referencing your CMK in the KMS, the bsonType of the plaintext data, and the algorithm. The algorithm is crucial; AEAD_AES_256_CBC_HMAC_SHA_256 is recommended for authenticated encryption, providing both confidentiality and integrity. Your KMS must be configured with permissions for the application’s identity to both encrypt and decrypt using the specified CMK.
A common point of confusion is the role of the keyId. This isn’t a key itself, but a pointer to a key stored and managed by your external KMS. The driver uses this ID to tell the KMS which CMK to use for encryption or decryption. The actual cryptographic operations happen within the KMS, keeping the raw keys out of your application code and the MongoDB server.
When you configure FLE, the autoEncryptionOpts on your MongoDB driver connection are paramount. This object tells the driver to automatically manage encryption and decryption based on the schema applied to your collections, and it requires specifying the keyVaultNamespace (e.g., encryption.__keyVault) where MongoDB stores metadata about your encryption keys, and the kmsProviders configuration, detailing how to connect to your chosen KMS.
The next hurdle you’ll likely encounter is managing key rotation and ensuring all your application instances are correctly configured with KMS access.