Docs Menu
Docs Home
/ / /
Mongoid
/

Client-Side Field Level Encryption

On this page

  • Overview
  • Install Dependencies
  • libmongocrypt
  • Shared Library (Driver v2.19 or later)
  • mongocryptd (Driver v2.18 or earlier)
  • ffi
  • Create a Customer Master Key
  • Configure your Client
  • Create a Data Encryption Key
  • Configure Encryption Schema
  • Limitations
  • Working with Data
  • Rotate Encryption Keys
  • Add Automatic Encryption to Existing Project
  • Additional Information

In this guide, you can learn how to encrypt your data by using client-side field level encryption (CSFLE). CSFLE allows you to encrypt data in your application before sending it over the network to MongoDB. This means that no MongoDB product has access to your data in unencrypted form.

You can set up CSFLE by using one of the following mechanisms:

  • Automatic encryption: Allows you to perform encrypted read and write operations without specifying how to encrypt fields

  • Explicit encryption: Allows you to perform encrypted read and write operations with specified encryption logic throughout your application.

This guide describes how to set up CSFLE with automatic encryption. To learn more about using explicit encryption, see the Explicit Encryption guide in the Ruby driver documentation.

To use CSFLE with Mongoid, you must first install the following dependencies:

  • libmongocrypt

  • Automatic Encryption Shared Library if you are using Ruby driver v2.19 or later. Or mongocryptd if you are using Ruby driver v2.18 or earlier.

  • ffi

The following sections provide details on how to install these dependencies.

You can install libmongocrypt by adding the libmongocrypt-helper gem to your Gemfile or by downloading the library manually.

To install libmongocrypt by adding the gem file, navigate to the folder in which your application is located and run the following command in your shell:

gem install libmongocrypt-helper --pre

Note

Because the version number of libmongocrypt-helper might contain letters, which indicates a pre-release version in Ruby, the --pre flag is required.

To learn how to download and install the library manually, see the libmongocrypt installation guide in the Ruby driver documentation.

The following steps detail how to install the Automatic Encryption Shared Library:

  1. In a browser, navigate to the MongoDB Download Center.

  2. Select the latest current version in the Version dropdown, denoted by the (current) tag.

  3. Select your platform in the Platform dropdown.

  4. Select crypt_shared in the Package dropdown.

  5. Click the Download button to download the shared library.

After you download the file, extract the contents and save the file in a location that your application can access. Then, configure your mongoid.yml file in your application to point to the library, as shown in the following example:

development:
clients:
default:
options:
auto_encryption_options:
extra_options:
crypt_shared_lib_path: '<Path to Shared Library>'

If you are using Ruby driver version 2.18 or earlier, you must use mongocryptd instead of the Automatic Encryption Shared Library. mongocryptd comes pre-packaged with enterprise builds of MongoDB Server. For instructions on how to install and configure mongocryptd, see the Install mongocryptd guide in the MongoDB Server manual.

Mongoid uses the ffi gem to call functions from libmongocrypt. Add the gem to your Gemfile by running the following command in your shell:

gem 'ffi'

To encrypt and decrypt data, you must first create a Customer Master Key (CMK). A CMK is a key that you use to encrypt your Data Encryption Key (DEK). Without access to a CMK, your client application cannot decrypt DEKs associated with your encrypted data.

You can create a locally-stored key to use as a local CMK for testing purposes by running the following Ruby code:

require 'securerandom'
SecureRandom.hex(48)

Warning

Using a local CMK in a production environment is insecure. For production environments, use a remote key management service to create and store your CMK.

To learn more about key management service providers, see the KMS Providers guide in the MongoDB Server manual.

You must configure your MongoDB client to implement CSFLE. To configure a client for CSFLE, add the following code to your mongoid.yml file:

development:
clients:
default:
uri: "<connection string>"
options:
auto_encryption_options: # This key enables automatic encryption
key_vault_namespace: 'encryption.__keyVault' # Database and collection in which to store data keys
kms_providers: # Tells the driver where to obtain master keys
local: # Specifies that the key is local
key: "<Path to your CMK>"
extra_options:
crypt_shared_lib_path: '<Path to Shared Library>' # Only required for Ruby versions 2.19 or later

Note

Ensure that you replace the placeholders surrounded by brackets (<>) in the preceding code example.

A Data Encryption Key (DEK) is a key that you use to encrypt the fields in your documents. MongoDB stores DEKs, encrypted with your CMK, in the Key Vault collection as BSON documents. MongoDB can never decrypt the DEKs, as key management is client-side and customer controlled.

To create a DEK in Mongoid, you can use the db:mongoid:encryption:create_data_key rake task, as shown in the following example:

rake db:mongoid:encryption:create_data_key

You can create multiple DEKs by repeating the preceding command for the number of keys you want to generate.

You can also provide an alternate name for your DEK. This allows you to reference the DEK by name when configuring encryption for your fields and to dynamically assign a DEK to a field at runtime.

The following example creates an alternate name when generating a new DEK:

rake db:mongoid:encryption:create_data_key -- --key-alt-name=<custom DEK name>

You can specify which fields to encrypt by adding the encrypt option to the field definition in your models and specifying the deterministic and key_id options, as shown in the following example:

class Patient
include Mongoid::Document
include Mongoid::Timestamps
encrypt_with key_id: '<data encryption key>'
# This field is not encrypted
field :category, type: String
# This field is encrypted by using AEAD_AES_256_CBC_HMAC_SHA_512-Random
# algorithm
field :passport_id, type: String, encrypt: {
deterministic: false
}
# This field is encrypted by using AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic
# algorithm
field :blood_type, type: String, encrypt: {
deterministic: true
}
# This field is encrypted by using AEAD_AES_256_CBC_HMAC_SHA_512-Random
# algorithm and a different data key
field :ssn, type: Integer, encrypt: {
deterministic: false, key_id: '<New key ID'
}
embeds_one :insurance
end
class Insurance
include Mongoid::Document
include Mongoid::Timestamps
field :insurer, type: String
# This field is encrypted using AEAD_AES_256_CBC_HMAC_SHA_512-Random
# algorithm using a key with an alternate name stored in the policy_number_key field
field :policy_number, type: Integer, encrypt: {
deterministic: false,
key_name_field: :policy_number_key
}
embedded_in :patient
end

Note

If you are developing a Rails application, we recommend setting the preload_models option to true in your mongoid.yml file. This ensures that Mongoid loads all models and configures the encryption schema before any data is read or written.

The following limitations apply when using CSFLE with Mongoid:

  • Mongoid does not support encryption of embeds_many associations.

  • If you use the :key_name_field option, you must encrypt the field by using a non-deterministic algorithm. To encrypt your field deterministically, you must specify the :key_id option instead.

  • The limitations listed on the CSFLE Limitations page in the MongoDB Server manual also apply to Mongoid.

Usually, automatic CSLFE works transparently in your application. After your application is configured for CSFLE, you can create documents as usual and Mongoid automatically encrypts and decrypts them according to your configuration.

The following example creates a new Patient document in an application configured for CSFLE. It then uses a client called unencrypted_client that is connected to the database but not configured for CSFLE to read the document.

Patient.create!(
category: 'ER',
passport_id: '123456',
blood_type: 'AB+',
ssn: 98765,
insurance: Insurance.new(insurer: 'TK', policy_number: 123456, policy_number_key: 'my_data_key')
)
# Fields are encrypted in the database
unencrypted_client['patients'].find.first
{"_id"=>BSON::ObjectId('6446a1d046ebfd701f9f4292'),
"category"=>"ER",
"passport_id"=><BSON::Binary:0x404080 type=ciphertext data=0x012889b2cb0b1341...>,
"blood_type"=><BSON::Binary:0x404560 type=ciphertext data=0x022889b2cb0b1341...>,
"ssn"=><BSON::Binary:0x405040 type=ciphertext data=0x012889b2cb0b1341...>,
"insurance"=>{"_id"=>BSON::ObjectId('6446a1d046ebfd701f9f4293'),
"insurer"=>"TK", "policy_number"=><BSON::Binary:0x405920 type=ciphertext
data=0x012889b2cb0b1341...>}, "policy_number_key"=>"my_data_key"}

In the preceding example, the unencrypted_client client is unable to read the encrypted fields. However, if you query the document with a client that is configured for CSFLE, Mongoid automatically decrypts the fields.

You can rotate your encryption keys by using the rewrap_many_data_key Ruby driver method. This method automatically decrypts multiple data encryption keys and re-encrypts them using a specified CMK. It then updates the rotated keys in the key vault collection.

The rewrap_many_data_key method takes the following parameters:

  • Filter, used to specify which fields to rotate. If no data key matches the given filter, no keys will be rotated. Omit the filter to rotate all keys in your key vault collection.

  • Object that represents a new CMK with which to re-encrypt the DEKs. Omit this object to rotate the data keys by using their current CMKs.

The following example rotates encryption keys by using the AWS KMS:

# Create a key vault client
key_vault_client = Mongo::Client.new('<connection string>')
# Create the encryption object
encryption = Mongo::ClientEncryption.new(
key_vault_client,
key_vault_namespace: 'encryption.__keyVault',
kms_providers: {
aws: {
"accessKeyId": "<IAM User Access Key ID>",
"secretAccessKey": "<IAM User Secret Access Key>"
}
}
)
encryption.rewrap_many_data_key(
{}, # Empty filter to rewrap all keys
{
provider: 'aws',
master_key: {
region: 'us-east-2',
key: 'arn:aws:kms:us-east-2:...'
}
}
)

Automatic CSFLE with Mongoid supports encryption in place. You can enable encryption on an existing database and still read unencrypted data. However, once you enable encryption, all new data is encrypted, and any query operation uses only the encrypted documents. This means that queries might not return all documents if some were saved before enabling encryption.

The following example queries a collection that has one encrypted document and one unencrypted document:

# Print all documents in the collection. The first document is unencrypted, and
# the second is encrypted.
Patient.all.to_a
# =>
# [#<Patient _id: 644937ac46ebfd02468e58c8, category: "ER", passport_id: "DE-1257", blood_type: "AB+", ssn: 123456>,
# #<Patient _id: 644937c946ebfd029309b912, category: "ER", passport_id: "AT-1545", blood_type: "AB+", ssn: 987654>]
# Querying for documents with a CSFLE-enabled client returns only the encrypted document
Patient.where(blood_type: 'AB+').to_a
# => [#<Patient _id: 644937c946ebfd029309b912, category: "ER", passport_id: "AT-1545", blood_type: "AB+", ssn: 987654>]

You can encrypt existing data in a collection by reading and then writing back all data with a CSFLE-enabled client. When doing so, ensure that all existing data is the expected type and that empty values are not set as nil.

To learn more about CSFLE, see the Client-Side Field Level Encryption guide in the MongoDB Server manual.

To learn more about using CSFLE with the Ruby driver, see the Client-Side Encryption guide in the Ruby driver documentation.

To learn more about configuring Mongoid in your application, see the Application Configuration guide.

Back

Secure Your Data