Skip to content

Instantly share code, notes, and snippets.

@kennwhite
Last active October 16, 2019 17:12
Show Gist options
  • Save kennwhite/ac586cfa1f8673a5cbec8c8b91e29bbc to your computer and use it in GitHub Desktop.
Save kennwhite/ac586cfa1f8673a5cbec8c8b91e29bbc to your computer and use it in GitHub Desktop.
MongoDB Client Side Field Level Encryption Quickstart Part 2 (KMS version)
// Simple demonstration using MongoDB Client-Side Field Level Encryption (KMS version)
// Requires Community or (preferrably) Enterprise Shell and a MongoDB 4.2+ database
// Local, stand-alone, or Atlas MongoDB will all work.
// To use this, just open Mongo shell, with this file, e.g.: `mongo localhost --shell hello_world_shell_kms.js`
// Note, you will need the attached `kms_config.env` file, see below.
// See: Client-Side Field Level Encryption Quickstart Part 1:
// https://gist.github.com/kennwhite/e64e5b6770e89a797c3a08ecaa0cb7d0
var demoDB = "demoFLE"
var keyVaultColl = "__keystore" // nothing special about this key vault collection name, but make it stand out
const ENC_DETERM = 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'
const ENC_RANDOM = 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'
// populate AWS & connection string variables
var env = {}
print("\nLoading connection & key settings file...")
try {
load( 'kms_config.env' );
} catch (err) {
print("Exiting: Unable to open file: " + envFile );
quit()
}
if (env.KMSKEY == "xxxxxxxxxxxxxxxxxxxxxxxxx"){
print("\nPlease generate a KMS key & IAM credentials (see `kms_config.env` file). Exiting. \n\n"); quit();
}
var clientSideFLEOptions = {
"kmsProviders" : {
"aws" : {
"accessKeyId" : env.KMSKID ,
"secretAccessKey" : env.KMSKEY
}
},
schemaMap: {}, // on first invocation prior to field key generation, this should be empty
keyVaultNamespace: demoDB + "." + keyVaultColl
};
encryptedSession = new Mongo(env.connStr, clientSideFLEOptions);
// javascript shell script equivalent of: use demoFLE
db = encryptedSession.getDB( demoDB )
// Wipe sandbox. Approximate Atlas equivalent of: db.dropDatabase()
db.getCollectionNames().forEach(function(c){db.getCollection(c).drop()});
var keyVault = encryptedSession.getKeyVault();
print("Attempting to create field keys...")
keyVault.createKey("aws", env.KMSARN, ["fieldKey1"])
keyVault.createKey("aws", env.KMSARN, ["fieldKey2"])
keyVault
db.getCollection( keyVaultColl ).find().pretty()
print("Attempting to retrieve field keys...")
var key1 = db.getCollection( keyVaultColl ).find({ keyAltNames: 'fieldKey1' }).toArray()[0]._id
var key2 = db.getCollection( keyVaultColl ).find({ keyAltNames: 'fieldKey2' }).toArray()[0]._id
print("Setting server-side json schema for automatic encryption on `people` collection...")
db.createCollection("people")
db.runCommand({
collMod: "people",
validator: {
$jsonSchema: {
"bsonType": "object",
"properties": {
"ssn": { bsonType: "binData" },
"dob": { bsonType: "binData" },
}
}
}
})
print("Creating client-side json schema config for automatic encryption on `people` collection...")
var peopleSchema = {
"demoFLE.people": {
"bsonType": "object",
"properties": {
"ssn": {
"encrypt": {
"bsonType": "string",
"algorithm": ENC_DETERM,
"keyId": [ key1 ]
}
},
"dob": {
"encrypt": {
"bsonType": "date",
"algorithm": ENC_RANDOM,
"keyId": [ key1 ]
}
},
"contact": {
"bsonType": "object",
"properties": {
"email": {
"encrypt": {
"bsonType": "string",
"algorithm": ENC_DETERM,
"keyId": [ key2 ]
}
},
"mobile": {
"encrypt": {
"bsonType": "string",
"algorithm": ENC_DETERM,
"keyId": [ key2 ]
}
}
},
},
}
}
}
print("Updating FLE mode session to enable server- and client-side json schema for automatic encryption...")
var clientSideFLEOptions = {
"kmsProviders": {
"aws": {
"accessKeyId": env.KMSKID,
"secretAccessKey": env.KMSKEY
}
},
schemaMap: peopleSchema,
keyVaultNamespace: demoDB + "." + keyVaultColl
}
var encryptedSession = new Mongo(env.connStr, clientSideFLEOptions)
var db = encryptedSession.getDB( demoDB );
print("Attempting to detect server-side Enterprise edition mode...")
var edition = db.runCommand({buildInfo:1}).modules
var enterprise = false
if ( edition !== undefined && edition.length != 0 ){
var enterprise = true
}
print("MongoDB server running in enterprise mode: " + enterprise + "\n")
print("Attempting to insert sample document with automatic encryption...")
try {
var res = null
res = db.people.insert({
firstName: 'Grace',
lastName: 'Hopper',
ssn: "901-01-0001",
dob: new Date('1989-12-13'),
address: {
street: '123 Main Street',
city: 'Omaha',
state: 'Nebraska',
zip: '90210'
},
contact: {
mobile: '202-555-1212',
email: '[email protected]',
}
})
} catch (err) {
res = err
}
print("Result: " + res)
print("Attempting to insert sample document with explicit encryption...")
try{
var res = null
res = db.people.insert({
firstName: 'Alan',
lastName: 'Turing',
ssn: db.getMongo().encrypt( key1 , "901-01-0002" , ENC_DETERM ),
dob: db.getMongo().encrypt( key1 , new Date('1912-06-23'), ENC_RANDOM ),
address: {
street: '123 Oak Lane',
city: 'Cleveland',
state: 'Ohio',
zip: '90210'
},
contact: {
mobile: db.getMongo().encrypt( key2 , '202-555-1234', ENC_DETERM ),
email: db.getMongo().encrypt( key2 , '[email protected]', ENC_DETERM ),
}
})
} catch (err) {
res = err
}
print("Result: " + res)
print("\nEnabling session bypass on automatic encrypt/decrypt... \n")
var clientSideFLEOptions = {
"kmsProviders": {
"aws": {
"accessKeyId": env.KMSKID,
"secretAccessKey": env.KMSKEY
}
},
bypassAutoEncryption: true,
schemaMap: peopleSchema,
keyVaultNamespace: demoDB + "." + keyVaultColl
}
var encryptedSession = new Mongo(env.connStr, clientSideFLEOptions)
var db = encryptedSession.getDB( demoDB );
print("Attempting to insert sample document with explicit encryption...")
try{
var res = null
res = db.people.insert({
firstName: 'Alan',
lastName: 'Turing',
ssn: db.getMongo().encrypt( key1 , "901-01-0002" , ENC_DETERM ),
dob: db.getMongo().encrypt( key1 , new Date('1912-06-23'), ENC_RANDOM ),
address: {
street: '123 Oak Lane',
city: 'Cleveland',
state: 'Ohio',
zip: '90210'
},
contact: {
mobile: db.getMongo().encrypt( key2 , '202-555-1234', ENC_DETERM ),
email: db.getMongo().encrypt( key2 , '[email protected]', ENC_DETERM ),
}
})
} catch (err) {
res = err
}
print("Result: " + res)
print("Dumping (raw) records from `people`:")
var records = db.people.find().pretty()
while (records.hasNext()) {
printjson(records.next());
}
print("\nDisabling session bypass for automatic encrypt/decrypt...\n")
var clientSideFLEOptions = {
kmsProviders: {
aws: {
accessKeyId: env.KMSKID,
secretAccessKey: env.KMSKEY
}
},
schemaMap: peopleSchema,
keyVaultNamespace: demoDB + "." + keyVaultColl
}
var encryptedSession = new Mongo(env.connStr, clientSideFLEOptions)
var db = encryptedSession.getDB( demoDB );
print("Dumping (automatic decrypted) records from `people`:")
var records = db.people.find().pretty()
while (records.hasNext()) {
printjson(records.next());
}
print("\nDemo complete.")
// Database host connection string. For Atlas, e.g.: "mongodb+srv://dbuser01:[email protected]"
env.connStr = "localhost"
// This is the KMS IAM AWS Key ID (see Quickstart Part 1 for the values below)
env.KMSKID = "AKIxxxxxxxx"
// This is the KMS IAM Secret Key
env.KMSKEY = "xxxxxxxxxxxxxxxxxxxxxxxxx"
// This is the KMS Master Key AWS ARN
env.KMSARN = "arn:aws:kms:us-east-1:12345678:key/123456-1234-1234-1234-123456789"
$ mongo localhost refactor_atlas.js
MongoDB shell version v4.2.0
[...]
Implicit session: session { "id" : UUID("db61b4f1-ac41-4a31-b11a-b964e3a469ce") }
MongoDB server version: 4.2.0
Loading connection & key settings file...
Attempting to create field keys...
Attempting to retrieve field keys...
Setting server-side json schema for automatic encryption on `people` collection...
Creating client-side json schema config for automatic encryption on `people` collection...
Updating FLE mode session to enable server- and client-side json schema for automatic encryption...
Attempting to detect server-side Enterprise edition mode...
MongoDB server running in enterprise mode: true
Attempting to insert sample document with automatic encryption...
Result: WriteResult({ "nInserted" : 1 })
Attempting to insert sample document with explicit encryption...
Result: Error: Cannot encrypt element of type binData because schema requires that type is one of: [ string ]
Enabling session bypass on automatic encrypt/decrypt...
Attempting to insert sample document with explicit encryption...
Result: WriteResult({ "nInserted" : 1 })
Dumping (raw) records from `people`
{
"_id" : ObjectId("5d69554415098d520aa7f4a6"),
"firstName" : "Grace",
"lastName" : "Hopper",
"ssn" : BinData(6,"Aa+ZP9KU2EfEty4csdYHca4Cz0Lhm4WhZxz4Vi5aiRD0bySp/7D70UYcHkHLQ9+NjA5EleMKmPO9eqeWU5vHx0Cj/MgcerxAu63dFGmVxVDXAxSDqN9uuZiom1WR69sRIhU="),
"dob" : BinData(6,"Aq+ZP9KU2EfEty4csdYHca4JjDrGBd9jQg4X/nuNJtNXKxgxMzhaAs6ES3mIa8KgOLOmIsuzmtcaTxiWfQ3/4BMot8OhCnNyZebsjwmO+BUvyQ=="),
"address" : {
"street" : "123 Main Street",
"city" : "Omaha",
"state" : "Nebraska",
"zip" : "90210"
},
"contact" : {
"mobile" : BinData(6,"AT297A95l0jDkcqeJ8xSZ/UCSh38UNgi8VBkd78T1tVASQyUxlkAtoR5g8MQrSiwjp5CU9M0XcFXnZteN00+f2wiDk8tnP3aPfdRWgS5nzjfxhcPkv3PJYSUSSZK5G0W12A="),
"email" : BinData(6,"AT297A95l0jDkcqeJ8xSZ/UCcDFY+Z4O9TV4HE68+I7U79878NgaD4LXRmMn8DUcdi7rFsZei140/rCTL9BoH4SLLhU9Hv2nT9W09vCt4SBVvU4ql9hHm9vEq8PCn3N8h10=")
}
}
{
"_id" : ObjectId("5d69554515098d520aa7f4a8"),
"firstName" : "Alan",
"lastName" : "Turing",
"ssn" : BinData(6,"Aa+ZP9KU2EfEty4csdYHca4Cs3QqsRJe2GcIalTeldS6RdLQ8gIoHA0lWak7CgoBzbxcW0KDmf3C50/zmvJx9VOuM1DYI63xJdkJ/DYz7yuTON7GFBRgduGvpALtVwtjAOw="),
"dob" : BinData(6,"Aq+ZP9KU2EfEty4csdYHca4JwWP/RMRIaO7HuEepbONVDv32jYTX7bSfAi8++ajC3LU5MbnFjw9bjuYw2LD9S/N2z6MULbF1PG1JTnvl4Xfqaw=="),
"address" : {
"street" : "123 Oak Lane",
"city" : "Cleveland",
"state" : "Ohio",
"zip" : "90210"
},
"contact" : {
"mobile" : BinData(6,"AT297A95l0jDkcqeJ8xSZ/UCAavFkesDhvIbzx9taq7XzRblXMmz2BDs0ADcLvZwtjgAywsGco1WSL3sUToeye8nVpIcMifz8E/d2+WOB33f7JfUARH0VmvzXn+6mc99KXM="),
"email" : BinData(6,"AT297A95l0jDkcqeJ8xSZ/UCudkM45g77Xic3S6xr1pjuIHxq9iIdsclkqaMyr+Jp0WxFPk06QGPt4fN9knC7a9oHtM+WkB5OUuzolUgV/EB7iegorDBk9k5gDdbcaSPEJE=")
}
}
Disabling session bypass for automatic encrypt/decrypt...
Dumping (automatic decrypted) records in `people`
{
"_id" : ObjectId("5d69554415098d520aa7f4a6"),
"firstName" : "Grace",
"lastName" : "Hopper",
"ssn" : "901-01-0001",
"dob" : ISODate("1989-12-13T00:00:00Z"),
"address" : {
"street" : "123 Main Street",
"city" : "Omaha",
"state" : "Nebraska",
"zip" : "90210"
},
"contact" : {
"mobile" : "202-555-1212",
"email" : "[email protected]"
}
}
{
"_id" : ObjectId("5d69554515098d520aa7f4a8"),
"firstName" : "Alan",
"lastName" : "Turing",
"ssn" : "901-01-0002",
"dob" : ISODate("1912-06-23T00:00:00Z"),
"address" : {
"street" : "123 Oak Lane",
"city" : "Cleveland",
"state" : "Ohio",
"zip" : "90210"
},
"contact" : {
"mobile" : "202-555-1234",
"email" : "[email protected]"
}
}
Demo complete.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment