Docs Menu
Docs Home
/
MongoDB Manual
/ / / / /

Use Automatic Client-Side Field Level Encryption with GCP

On this page

  • Overview
  • Before You Get Started
  • Set Up the KMS
  • Register a GCP Service Account
  • Create a GCP Customer Master Key
  • Create the Application
  • Create a Unique Index on your Key Vault collection
  • Create a Data Encryption Key
  • Configure the MongoClient
  • Insert a Document with Encrypted Fields
  • Retrieve Your Document with Encrypted Fields
  • Learn More

This guide shows you how to build a Client-Side Field Level Encryption (CSFLE)-enabled application using Google Cloud Key Management Service.

After you complete the steps in this guide, you should have:

  • A CMK hosted on Google Cloud Key Management Service.

  • A client application that inserts documents with encrypted fields using your CMK.

To complete and run the code in this guide, you need to set up your development environment as shown in the Installation Requirements page.

Throughout this guide, code examples use placeholder text. Before you run the examples, substitute your own values for these placeholders.

For example:

dek_id := "<Your Base64 DEK ID>"

You would replace everything between quotes with your DEK ID.

dek_id := "abc123"

Select the programming language for which you want to see code examples for from the Select your language dropdown menu on the right side of the page.

Tip

See: Full Application

To view the complete runnable application code for this tutorial, go to the following link:

Complete C# Application

// You are viewing the C# driver code examples.
// Use the dropdown menu to select a different driver.
// You are viewing the Golang driver code examples.
// Use the dropdown menu to select a different driver.

Important

When building or running the Golang code in this guide using go build or go run, always include the cse build constraint to enable CSFLE. See the following shell command for an example of including the build constraint:

go run -tags cse insert-encrypted-document.go
// You are viewing the Java synchronous driver code examples.
// Use the dropdown menu to select a different driver.
// You are viewing the Node.js driver code examples.
// Use the dropdown menu to select a different driver.
# You are viewing the Python driver code examples.
# Use the dropdown menu to select a different driver.
1
1
2

To create a service account on Google Cloud, follow the Creating a service account guide in Google's official documentation.

3

To add a service account key on Google Cloud, follow the Managing service account keys guide in Google's official documentation.

Important

When creating your service account key, you receive a one-time download of the private key information. Make sure to download this file in either the PKCS12 or JSON format for use later in this tutorial.

Important

When creating your service account key, you receive a one-time download of the private key information. Make sure to download this file in either the PKCS12 or JSON format for use later in this tutorial.

Important

When creating your service account key, you receive a one-time download of the private key information. Unless you are using an attached service account, make sure to download this file in either the PKCS12 or JSON format for use later in this tutorial.

Important

When creating your service account key, you receive a one-time download of the private key information. Make sure to download this file in either the PKCS12 or JSON format for use later in this tutorial.

Important

When creating your service account key, you receive a one-time download of the private key information. Make sure to download this file in either the PKCS12 or JSON format for use later in this tutorial.

2
1

Create a key ring and a symmetric key by following the Create a key guide from Google's official documentation.

This key is your Customer Master Key (CMK).

Record the following details of your CMK for use in a future step of this tutorial.

Field
Required
Description
key_name
Yes
Identifier for the CMK.
key_ring
Yes
Identifier for the group of keys your key belongs to.
key_version
No
The version of the named key.
location
Yes
Region specified for your key.
endpoint
No
The host and optional port of the Google Cloud KMS. The default value is cloudkms.googleapis.com.

Select the tab that corresponds to the MongoDB driver you are using in your application to see relevant code samples.

1

Create a unique index on the keyAltNames field in your encryption.__keyVault namespace.

Select the tab corresponding to your preferred MongoDB driver:

var connectionString = "<Your MongoDB URI>";
var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
var keyVaultClient = new MongoClient(connectionString);
var indexOptions = new CreateIndexOptions<BsonDocument>();
indexOptions.Unique = true;
indexOptions.PartialFilterExpression = new BsonDocument { { "keyAltNames", new BsonDocument { { "$exists", new BsonBoolean(true) } } } };
var builder = Builders<BsonDocument>.IndexKeys;
var indexKeysDocument = builder.Ascending("keyAltNames");
var indexModel = new CreateIndexModel<BsonDocument>(indexKeysDocument, indexOptions);
var keyVaultDatabase = keyVaultClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.ToString());
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName);
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
keyVaultClient.GetDatabase("medicalRecords").DropCollection("patients");
var keyVaultCollection = keyVaultDatabase.GetCollection<BsonDocument>(keyVaultNamespace.CollectionName.ToString());
keyVaultCollection.Indexes.CreateOne(indexModel);
uri := "<Your MongoDB URI>"
keyVaultClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
return fmt.Errorf("Connect error for regular client: %v", err)
}
defer func() {
_ = keyVaultClient.Disconnect(context.TODO())
}()
keyVaultColl := "__keyVault"
keyVaultDb := "encryption"
keyVaultNamespace := keyVaultDb + "." + keyVaultColl
keyVaultIndex := mongo.IndexModel{
Keys: bson.D{{"keyAltNames", 1}},
Options: options.Index().
SetUnique(true).
SetPartialFilterExpression(bson.D{
{"keyAltNames", bson.D{
{"$exists", true},
}},
}),
}
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
if err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Drop(context.TODO()); err != nil {
log.Fatalf("Collection.Drop error: %v", err)
}
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
if err = keyVaultClient.Database("medicalRecords").Collection("patients").Drop(context.TODO()); err != nil {
log.Fatalf("Collection.Drop error: %v", err)
}
_, err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Indexes().CreateOne(context.TODO(), keyVaultIndex)
if err != nil {
panic(err)
}
String connectionString = "<Your MongoDB URI>";
String keyVaultDb = "encryption";
String keyVaultColl = "__keyVault";
String keyVaultNamespace = keyVaultDb + "." + keyVaultColl;
MongoClient keyVaultClient = MongoClients.create(connectionString);
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl).drop();
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
keyVaultClient.getDatabase("medicalRecords").getCollection("patients").drop();
MongoCollection keyVaultCollection = keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl);
IndexOptions indexOpts = new IndexOptions().partialFilterExpression(new BsonDocument("keyAltNames", new BsonDocument("$exists", new BsonBoolean(true) ))).unique(true);
keyVaultCollection.createIndex(new BsonDocument("keyAltNames", new BsonInt32(1)), indexOpts);
keyVaultClient.close();
const uri = "<Your Connection String>";
const keyVaultDatabase = "encryption";
const keyVaultCollection = "__keyVault";
const keyVaultNamespace = `${keyVaultDatabase}.${keyVaultCollection}`;
const keyVaultClient = new MongoClient(uri);
await keyVaultClient.connect();
const keyVaultDB = keyVaultClient.db(keyVaultDatabase);
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
await keyVaultDB.dropDatabase();
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
await keyVaultClient.db("medicalRecords").dropDatabase();
const keyVaultColl = keyVaultDB.collection(keyVaultCollection);
await keyVaultColl.createIndex(
{ keyAltNames: 1 },
{
unique: true,
partialFilterExpression: { keyAltNames: { $exists: true } },
}
);
connection_string = "<your connection string here>"
key_vault_coll = "__keyVault"
key_vault_db = "encryption"
key_vault_namespace = f"{key_vault_db}.{key_vault_coll}"
key_vault_client = MongoClient(connection_string)
# Drop the Key Vault Collection in case you created this collection
# in a previous run of this application.
key_vault_client.drop_database(key_vault_db)
# Drop the database storing your encrypted fields as all
# the DEKs encrypting those fields were deleted in the preceding line.
key_vault_client["medicalRecords"].drop_collection("patients")
key_vault_client[key_vault_db][key_vault_coll].create_index(
[("keyAltNames", ASCENDING)],
unique=True,
partialFilterExpression={"keyAltNames": {"$exists": True}},
)
2
1

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
var provider = "gcp";
var gcpKmsOptions = new Dictionary<string, object>
{
{ "privateKey", "<Your GCP Private Key>" },
{ "email", "<Your GCP Email>" },
};
kmsProviders.Add(provider, gcpKmsOptions);

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

provider := "gcp"
kmsProviders := map[string]map[string]interface{}{
provider: {
"email": "<Your GCP Email>",
"privateKey": "<Your GCP Private Key>",
},
}

Tip

Attached Service Account

If you are using an attached service account, you can allow it to automatically authenticate it to your GCP KMS.

To automatically authenticate, assign an empty map instead of one that contains your GCP credentials, as shown in the following code:

String kmsProvider = "gcp";
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
Map<String, Object> providerDetails = new HashMap<>();
kmsProviders.put(kmsProvider, providerDetails);

Proceed to the next step in the guide after adding this code.

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

String kmsProvider = "gcp";
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
Map<String, Object> providerDetails = new HashMap<>();
providerDetails.put("email", "<Your GCP Email Address>");
providerDetails.put("privateKey", "<Your GCP Private Key>");
kmsProviders.put(kmsProvider, providerDetails);

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

const provider = "gcp";
const kmsProviders = {
gcp: {
email: "<Your GCP Email>",
privateKey: "<Your GCP Private Key>",
},
};

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

provider = "gcp"
kms_providers = {
provider: {"email": "<your GCP email>", "privateKey": "<your GCP private key>"}
}

Tip

You saved a file containing your service account key credentials in the Create a GCP Service Account step of this guide.

If you downloaded your credentials in JSON format, you can use the following command to extract the value of your private key, substituting <credentials-filename> with the name of your credentials file. The following command requires that you install OpenSSL:

cat <credentials-filename> | jq -r .private_key | openssl pkcs8 -topk8 -nocrypt -inform PEM -outform DER | base64

If you downloaded your credentials in PKCS12 format, you need to specify your GCP service account import password and to add a PEM pass phrase to access the key when accessing it using the following command, substituting <credentials-filename> with the name of your credentials file:

openssl pkcs12 -info -in <credentials-filename>
2

Update the following code to specify your Customer Master Key:

Tip

You recorded your Customer Master Key details in the in the Create a Customer Master Key step of this guide.

var dataKeyOptions = new DataKeyOptions(
masterKey: new BsonDocument
{
{ "projectId", "Your GCP Project ID" },
{ "location", "Your GCP Key Location" } ,
{ "keyRing", "<Your GCP Key Ring>" },
{ "keyName", "<Your GCP Key Name>" },
});
masterKey := map[string]interface{}{
"projectId": "<Your GCP Project ID>",
"location": "<Your GCP Location>",
"keyRing": "<Your GCP Key Ring>",
"keyName": "<Your GCP Key Name>",
}
BsonDocument masterKeyProperties = new BsonDocument();
masterKeyProperties.put("provider", new BsonString(kmsProvider));
masterKeyProperties.put("projectId", new BsonString("<Your GCP Project ID>"));
masterKeyProperties.put("location", new BsonString("<Your GCP Key Location>"));
masterKeyProperties.put("keyRing", new BsonString("<Your GCP Key Ring>"));
masterKeyProperties.put("keyName", new BsonString("<Your GCP Key Name>"));
const masterKey = {
projectId: "<Your Project ID>",
location: "<Your Key Location>",
keyRing: "<Your Key Ring>",
keyName: "<Your Key Name>",
};
master_key = {
"projectId": "<GCP project identifier>",
"location": "<GCP region>",
"keyRing": "<GCP key ring name>",
"keyName": "<GCP key name>",
}
3

Generate your Data Encryption Key using the variables declared in step one of this tutorial.

var clientEncryptionOptions = new ClientEncryptionOptions(
keyVaultClient: keyVaultClient,
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders
);
var clientEncryption = new ClientEncryption(clientEncryptionOptions);
var dataKeyId = clientEncryption.CreateDataKey(provider, dataKeyOptions, CancellationToken.None);
var dataKeyIdBase64 = Convert.ToBase64String(GuidConverter.ToBytes(dataKeyId, GuidRepresentation.Standard));
Console.WriteLine($"DataKeyId [base64]: {dataKeyIdBase64}");
clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(keyVaultNamespace).
SetKmsProviders(kmsProviders)
clientEnc, err := mongo.NewClientEncryption(keyVaultClient, clientEncryptionOpts)
if err != nil {
return fmt.Errorf("NewClientEncryption error %v", err)
}
defer func() {
_ = clientEnc.Close(context.TODO())
}()
dataKeyOpts := options.DataKey().
SetMasterKey(masterKey)
dataKeyID, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts)
if err != nil {
return fmt.Errorf("create data key error %v", err)
}
fmt.Printf("DataKeyId [base64]: %s\n", base64.StdEncoding.EncodeToString(dataKeyID.Data))
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
.keyVaultMongoClientSettings(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.build())
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.build();
MongoClient regularClient = MongoClients.create(connectionString);
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
BsonBinary dataKeyId = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions().masterKey(masterKeyProperties));
String base64DataKeyId = Base64.getEncoder().encodeToString(dataKeyId.getData());
System.out.println("DataKeyId [base64]: " + base64DataKeyId);
clientEncryption.close();
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
await client.connect();
const encryption = new ClientEncryption(client, {
keyVaultNamespace,
kmsProviders,
});
const key = await encryption.createDataKey(provider, {
masterKey: masterKey,
});
console.log("DataKeyId [base64]: ", key.toString("base64"));
await keyVaultClient.close();
await client.close();
key_vault_database = "encryption"
key_vault_collection = "__keyVault"
key_vault_namespace = f"{key_vault_database}.{key_vault_collection}"
client = MongoClient(connection_string)
client_encryption = ClientEncryption(
kms_providers, # pass in the kms_providers variable from the previous step
key_vault_namespace,
client,
CodecOptions(uuid_representation=STANDARD),
)
data_key_id = client_encryption.create_data_key(provider, master_key)
base_64_data_key_id = base64.b64encode(data_key_id)
print("DataKeyId [base64]: ", base_64_data_key_id)

Tip

Learn More

To view a diagram showing how your client application creates your Data Encryption Key when using an Google Cloud Key Management Service, see Architecture.

To learn more about the options for creating a Data Encryption Key encrypted with a Customer Master Key hosted in Azure Key Vault, see kmsProviders Object and dataKeyOpts Object.

Tip

See: Complete Code

To view the complete code for making a Data Encryption Key, see our Github repository.

To view the complete code for making a Data Encryption Key, see our Github repository.

To view the complete code for making a Data Encryption Key, see our Github repository.

To view the complete code for making a Data Encryption Key, see our Github repository.

To view the complete code for making a Data Encryption Key, see our Github repository.

3

Tip

Follow the remaining steps in this tutorial in a separate file from the one created in the previous steps.

To view the complete code for this file, see our Github repository

To view the complete code for this file, see our Github repository.

To view the complete code for this file, see our Github repository.

To view the complete code for this file, see our Github repository.

To view the complete code for this file, see our Github repository.

1

Specify encryption.__keyVault as the Key Vault collection namespace.

var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
keyVaultNamespace := "encryption.__keyVault"
String keyVaultNamespace = "encryption.__keyVault";
const keyVaultNamespace = "encryption.__keyVault";
key_vault_namespace = "encryption.__keyVault"
2

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
var provider = "gcp";
var gcpKmsOptions = new Dictionary<string, object>
{
{ "privateKey", "<Your GCP Private Key>" },
{ "email", "<Your GCP Email>" },
};
kmsProviders.Add(provider, gcpKmsOptions);

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

kmsProviders := map[string]map[string]interface{}{
"gcp": {
"email": "<Your GCP Email>",
"privateKey": "<Your GCP Private Key>",
},
}

Tip

Attached Service Account

If you are using an attached service account, you can allow it to automatically authenticate it to your GCP KMS.

To automatically authenticate, assign an empty map instead of one that contains your GCP credentials, as shown in the following code:

String kmsProvider = "gcp";
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
Map<String, Object> providerDetails = new HashMap<>();
kmsProviders.put(kmsProvider, providerDetails);

Proceed to the next step in the guide after adding this code.

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

String kmsProvider = "gcp";
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
Map<String, Object> providerDetails = new HashMap<>();
providerDetails.put("email", "<Your GCP Email Address>");
providerDetails.put("privateKey", "<Your GCP Private Key>");
kmsProviders.put(kmsProvider, providerDetails);

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

const kmsProviders = {
gcp: {
email: "<Your GCP Email>",
privateKey: "<Your GCP Private Key>",
},
};

Unless you're using an attached service account, add the service account credentials to your CSFLE-enabled client, as shown in the following code example:

provider = "gcp"
kms_providers = {
"gcp": {"email": "<your GCP email>", "privateKey": "<your GCP private key>"}
}
3

Tip

Add Your Data Encryption Key Base64 ID

Make sure to update the following code to include your Base64 DEK ID. You received this value in the Generate your Data Encryption Key step of this guide.

var keyId = "<Your base64 DEK ID here>";
var schema = new BsonDocument
{
{ "bsonType", "object" },
{
"encryptMetadata",
new BsonDocument("keyId", new BsonArray(new[] { new BsonBinaryData(Convert.FromBase64String(keyId), BsonBinarySubType.UuidStandard) }))
},
{
"properties",
new BsonDocument
{
{
"ssn", new BsonDocument
{
{
"encrypt", new BsonDocument
{
{ "bsonType", "int" },
{ "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" }
}
}
}
},
{
"bloodType", new BsonDocument
{
{
"encrypt", new BsonDocument
{
{ "bsonType", "string" },
{ "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random" }
}
}
}
},
{
"medicalRecords", new BsonDocument
{
{
"encrypt", new BsonDocument
{
{ "bsonType", "array" },
{ "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random" }
}
}
}
},
{
"insurance", new BsonDocument
{
{ "bsonType", "object" },
{
"properties", new BsonDocument
{
{
"policyNumber", new BsonDocument
{
{
"encrypt", new BsonDocument
{
{ "bsonType", "int" },
{ "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" }
}
}
}
}
}
}
}
}
}
}
};
var schemaMap = new Dictionary<string, BsonDocument>();
schemaMap.Add(dbNamespace, schema);
dek_id := "<Your Base64 DEK ID>"
schema_template := `{
"bsonType": "object",
"encryptMetadata": {
"keyId": [
{
"$binary": {
"base64": "%s",
"subType": "04"
}
}
]
},
"properties": {
"insurance": {
"bsonType": "object",
"properties": {
"policyNumber": {
"encrypt": {
"bsonType": "int",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
}
},
"medicalRecords": {
"encrypt": {
"bsonType": "array",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"bloodType": {
"encrypt": {
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"ssn": {
"encrypt": {
"bsonType": "int",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
}
}`
schema := fmt.Sprintf(schema_template, dek_id)
var schemaDoc bson.Raw
if err := bson.UnmarshalExtJSON([]byte(schema), true, &schemaDoc); err != nil {
return fmt.Errorf("UnmarshalExtJSON error: %v", err)
}
schemaMap := map[string]interface{}{
dbName + "." + collName: schemaDoc,
}
String dekId = "<paste-base-64-encoded-data-encryption-key-id>>";
Document jsonSchema = new Document().append("bsonType", "object").append("encryptMetadata",
new Document().append("keyId", new ArrayList<>((Arrays.asList(new Document().append("$binary", new Document()
.append("base64", dekId)
.append("subType", "04")))))))
.append("properties", new Document()
.append("ssn", new Document().append("encrypt", new Document()
.append("bsonType", "int")
.append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")))
.append("bloodType", new Document().append("encrypt", new Document()
.append("bsonType", "string")
.append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random")))
.append("medicalRecords", new Document().append("encrypt", new Document()
.append("bsonType", "array")
.append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random")))
.append("insurance", new Document()
.append("bsonType", "object")
.append("properties",
new Document().append("policyNumber", new Document().append("encrypt", new Document()
.append("bsonType", "int")
.append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"))))));
HashMap<String, BsonDocument> schemaMap = new HashMap<String, BsonDocument>();
schemaMap.put("medicalRecords.patients", BsonDocument.parse(jsonSchema.toJson()));
dataKey = "<Your base64 DEK ID>";
const schema = {
bsonType: "object",
encryptMetadata: {
keyId: [new Binary(Buffer.from(dataKey, "base64"), 4)],
},
properties: {
insurance: {
bsonType: "object",
properties: {
policyNumber: {
encrypt: {
bsonType: "int",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
},
},
},
},
medicalRecords: {
encrypt: {
bsonType: "array",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
},
},
bloodType: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
},
},
ssn: {
encrypt: {
bsonType: "int",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
},
},
},
};
var patientSchema = {};
patientSchema[namespace] = schema;
dek_id = b"<paste-base-64-encoded-data-encryption-key-id>"
json_schema = {
"bsonType": "object",
"encryptMetadata": {"keyId": [Binary(base64.b64decode(dek_id), UUID_SUBTYPE)]},
"properties": {
"insurance": {
"bsonType": "object",
"properties": {
"policyNumber": {
"encrypt": {
"bsonType": "int",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
}
}
},
},
"medicalRecords": {
"encrypt": {
"bsonType": "array",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
}
},
"bloodType": {
"encrypt": {
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
}
},
"ssn": {
"encrypt": {
"bsonType": "int",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
}
},
},
}
patient_schema = {"medicalRecords.patients": json_schema}
4

Configure the client to spawn the mongocryptd process by specifying the path to the binary using the following configuration options:

Note

Encryption Executable

If the mongocryptd.exe executable is not in the PATH, specify the spawn path.

var mongoBinariesPath = "<Path to mongocryptd binary>";
var extraOptions = new Dictionary<string, object>()
{
{ "mongocryptdSpawnPath", mongoBinariesPath },
};

Note

If mongocryptd is not in the PATH, specify the spawn path.

extraOptions := map[string]interface{}{
"mongocryptdSpawnPath": "<your path to mongocryptd>",
}

Note

Encryption Binary Daemon

If the mongocryptd daemon is already running, you can configure the client to skip starting it by passing the following option:

extraOptions := map[string]interface{}{
"mongocryptdBypassSpawn": true,
}
Map<String, Object> extraOptions = new HashMap<String, Object>();
extraOptions.put("mongocryptdSpawnPath", "<your path to mongocryptd>"));

Note

Encryption Binary Daemon

If the mongocryptd daemon is already running, you can configure the client to skip starting it by passing the following option:

extraOptions.put("mongocryptdBypassSpawn", true);
const extraOptions = {
mongocryptdSpawnPath: "<your path to mongocryptd>",
};

Note

Encryption Binary Daemon

If the mongocryptd daemon is already running, you can configure the client to skip starting it by passing the following option:

extraOptions.mongocryptdBypassSpawn = true;
extra_options = {"mongocryptd_spawn_path": "<your path to mongocryptd>"}

Note

Encryption Binary Daemon

If the mongocryptd daemon is already running, you can configure the client to skip starting it by passing the following option:

extra_options['mongocryptd_bypass_spawn'] = True
5

Instantiate a MongoDB client object with the following automatic encryption settings that use the variables declared in the previous steps:

var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
var autoEncryptionOptions = new AutoEncryptionOptions(
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders,
schemaMap: schemaMap,
extraOptions: extraOptions
);
clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
var secureClient = new MongoClient(clientSettings);
autoEncryptionOpts := options.AutoEncryption().
SetKmsProviders(kmsProviders).
SetKeyVaultNamespace(keyVaultNamespace).
SetSchemaMap(schemaMap).
SetExtraOptions(extraOptions)
secureClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri).SetAutoEncryptionOptions(autoEncryptionOpts))
if err != nil {
return fmt.Errorf("Connect error for encrypted client: %v", err)
}
defer func() {
_ = secureClient.Disconnect(context.TODO())
}()
MongoClientSettings clientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.autoEncryptionSettings(AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.schemaMap(schemaMap)
.extraOptions(extraOptions)
.build())
.build();
MongoClient mongoClientSecure = MongoClients.create(clientSettings);
const secureClient = new MongoClient(connectionString, {
useNewUrlParser: true,
useUnifiedTopology: true,
autoEncryption: {
keyVaultNamespace,
kmsProviders,
schemaMap: patientSchema,
extraOptions: extraOptions,
},
});
fle_opts = AutoEncryptionOpts(
kms_providers, key_vault_namespace, schema_map=patient_schema, **extra_options
)
secureClient = MongoClient(connection_string, auto_encryption_opts=fle_opts)
4

Use your CSFLE-enabled MongoClient instance to insert a document with encrypted fields into the medicalRecords.patients namespace using the following code snippet:

var sampleDocFields = new BsonDocument
{
{ "name", "Jon Doe" },
{ "ssn", 145014000 },
{ "bloodType", "AB-" },
{
"medicalRecords", new BsonArray
{
new BsonDocument("weight", 180),
new BsonDocument("bloodPressure", "120/80")
}
},
{
"insurance", new BsonDocument
{
{ "policyNumber", 123142 },
{ "provider", "MaestCare" }
}
}
};
// Construct an auto-encrypting client
var secureCollection = secureClient.GetDatabase(db).GetCollection<BsonDocument>(coll);
// Insert a document into the collection
secureCollection.InsertOne(sampleDocFields);
test_patient := map[string]interface{}{
"name": "Jon Doe",
"ssn": 241014209,
"bloodType": "AB+",
"medicalRecords": []map[string]interface{}{{
"weight": 180,
"bloodPressure": "120/80",
}},
"insurance": map[string]interface{}{
"provider": "MaestCare",
"policyNumber": 123142,
},
}
if _, err := secureClient.Database(dbName).Collection(collName).InsertOne(context.TODO(), test_patient); err != nil {
return fmt.Errorf("InsertOne error: %v", err)
}

Note

Rather than creating a raw BSON document, you can pass a struct with bson tags directly to the driver for encoding.

ArrayList<Document> medicalRecords = new ArrayList<>();
medicalRecords.add(new Document().append("weight", "180"));
medicalRecords.add(new Document().append("bloodPressure", "120/80"));
Document insurance = new Document()
.append("policyNumber", 123142)
.append("provider", "MaestCare");
Document patient = new Document()
.append("name", "Jon Doe")
.append("ssn", 241014209)
.append("bloodType", "AB+")
.append("medicalRecords", medicalRecords)
.append("insurance", insurance);
mongoClientSecure.getDatabase(recordsDb).getCollection(recordsColl).insertOne(patient);
try {
const writeResult = await secureClient
.db(db)
.collection(coll)
.insertOne({
name: "Jon Doe",
ssn: 241014209,
bloodType: "AB+",
medicalRecords: [{ weight: 180, bloodPressure: "120/80" }],
insurance: {
policyNumber: 123142,
provider: "MaestCare",
},
});
} catch (writeError) {
console.error("writeError occurred:", writeError);
}
def insert_patient(
collection, name, ssn, blood_type, medical_records, policy_number, provider
):
insurance = {"policyNumber": policy_number, "provider": provider}
doc = {
"name": name,
"ssn": ssn,
"bloodType": blood_type,
"medicalRecords": medical_records,
"insurance": insurance,
}
collection.insert_one(doc)
medical_record = [{"weight": 180, "bloodPressure": "120/80"}]
insert_patient(
secureClient.medicalRecords.patients,
"Jon Doe",
241014209,
"AB+",
medical_record,
123142,
"MaestCare",
)

When you insert a document, your CSFLE-enabled client encrypts the fields of your document such that it resembles the following:

{
"_id": { "$oid": "<_id of your document>" },
"name": "Jon Doe",
"ssn": {
"$binary": "<cipher-text>",
"$type": "6"
},
"bloodType": {
"$binary": "<cipher-text>",
"$type": "6"
},
"medicalRecords": {
"$binary": "<cipher-text>",
"$type": "6"
},
"insurance": {
"provider": "MaestCare",
"policyNumber": {
"$binary": "<cipher-text>",
"$type": "6"
}
}
}

Tip

See: Complete Code

To view the complete code for inserting a document with encrypted fields, see our Github repository

To view the complete code for inserting a document with encrypted fields, see our Github repository.

To view the complete code for inserting a document with encrypted fields, see our Github repository.

To view the complete code for inserting a document with encrypted fields, see our Github repository.

To view the complete code for inserting a document with encrypted fields, see our Github repository.

5

Retrieve the document with encrypted fields you inserted in the Insert a Document with Encrypted Fields step of this guide.

To show the functionality of CSFLE, the following code snippet queries for your document with a client configured for automatic CSFLE as well as a client that is not configured for automatic CSFLE.

Console.WriteLine("Finding a document with regular (non-encrypted) client.");
var filter = Builders<BsonDocument>.Filter.Eq("name", "Jon Doe");
var regularResult = regularCollection.Find(filter).Limit(1).ToList()[0];
Console.WriteLine($"\n{regularResult}\n");
Console.WriteLine("Finding a document with encrypted client, searching on an encrypted field");
var ssnFilter = Builders<BsonDocument>.Filter.Eq("ssn", 145014000);
var secureResult = secureCollection.Find(ssnFilter).Limit(1).First();
Console.WriteLine($"\n{secureResult}\n");
fmt.Println("Finding a document with regular (non-encrypted) client.")
var resultRegular bson.M
err = regularClient.Database(dbName).Collection(collName).FindOne(context.TODO(), bson.D{{"name", "Jon Doe"}}).Decode(&resultRegular)
if err != nil {
panic(err)
}
outputRegular, err := json.MarshalIndent(resultRegular, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("%s\n", outputRegular)
fmt.Println("Finding a document with encrypted client, searching on an encrypted field")
var resultSecure bson.M
err = secureClient.Database(dbName).Collection(collName).FindOne(context.TODO(), bson.D{{"ssn", "241014209"}}).Decode(&resultSecure)
if err != nil {
panic(err)
}
outputSecure, err := json.MarshalIndent(resultSecure, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("%s\n", outputSecure)
System.out.println("Finding a document with regular (non-encrypted) client.");
Document docRegular = mongoClientRegular.getDatabase(recordsDb).getCollection(recordsColl).find(eq("name", "Jon Doe")).first();
System.out.println(docRegular.toJson());
System.out.println("Finding a document with encrypted client, searching on an encrypted field");
Document docSecure = mongoClientSecure.getDatabase(recordsDb).getCollection(recordsColl).find(eq("ssn", 241014209)).first();
System.out.println(docSecure.toJson());
console.log("Finding a document with regular (non-encrypted) client.");
console.log(
await regularClient.db(db).collection(coll).findOne({ name: /Jon/ })
);
console.log(
"Finding a document with encrypted client, searching on an encrypted field"
);
console.log(
await secureClient.db(db).collection(coll).findOne({ ssn: "241014209" })
);
print("Finding a document with regular (non-encrypted) client.")
result = regularClient.medicalRecords.patients.find_one({"name": "Jon Doe"})
pprint.pprint(result)
print("Finding a document with encrypted client, searching on an encrypted field")
pprint.pprint(secureClient.medicalRecords.patients.find_one({"ssn": 241014209}))

The output of the preceding code snippet should look like this:

Finding a document with regular (non-encrypted) client.
{
_id: new ObjectId("629a452e0861b3130887103a"),
name: 'Jon Doe',
ssn: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e7910c20697e5f4fa95710aafc9153f0a3dc769c8a132a604b468732ff1f4d8349ded3244b59cbfb41444a210f28b21ea1b6c737508d9d30e8baa30c1d8070c4d5e26", "hex"), 6),
bloodType: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e79022e238536dfd8caadb4d7751ac940e0f195addd7e5c67b61022d02faa90283ab69e02303c7e4001d1996128428bf037dea8bbf59fbb20c583cbcff2bf3e2519b4", "hex"), 6),
'key-id': 'demo-data-key',
medicalRecords: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e790405163a3207cff175455106f57eef14e5610c49a99bcbd14a7db9c5284e45e3ee30c149354015f941440bf54725d6492fb3b8704bc7c411cff6c868e4e13c58233c3d5ed9593eca4e4d027d76d3705b6d1f3b3c9e2ceee195fd944b553eb27eee69e5e67c338f146f8445995664980bf0", "hex"), 6),
insurance: {
policyNumber: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e79108decd85c05be3fec099e015f9d26d9234605dc959cc1a19b63072f7ffda99db38c7b487de0572a03b2139ac3ee163bcc40c8508f366ce92a5dd36e38b3c742f7", "hex"), 6),
provider: 'MaestCare'
}
}
Finding a document with encrypted client, searching on an encrypted field
{
_id: new ObjectId("629a452e0861b3130887103a"),
name: 'Jon Doe',
ssn: 241014209,
bloodType: 'AB+',
'key-id': 'demo-data-key',
medicalRecords: [ { weight: 180, bloodPressure: '120/80' } ],
insurance: { policyNumber: 123142, provider: 'MaestCare' }
}

Tip

See: Complete Code

To view the complete code for finding a document with encrypted fields, see our Github repository

To view the complete code for finding a document with encrypted fields, see our Github repository.

To view the complete code for finding a document with encrypted fields, see our Github repository.

To view the complete code for finding a document with encrypted fields, see our Github repository.

To view the complete code for finding a document with encrypted fields, see our Github repository.

To learn more about the topics mentioned in this guide, see the following links:

  • Learn more about CSFLE components on the Reference page.

  • Learn how Customer Master Keys and Data Encryption Keys work on the Keys and Key Vaults page

  • See how KMS Providers manage your CSFLE keys on the KMS Providers page.

Back

Use Automatic Client-Side Field Level Encryption with Azure