Docs Menu

Docs HomeDevelop ApplicationsMongoDB DriversRuby MongoDB Driver

Queryable Encryption

Queryable encryption is a new feature in MongoDB 6.0. It also requires libmongocrypt version 1.5.2 or above.

You can find more information about queryable encryption in MongoDB Manual.

Note

The queryable encryption feature is in public technical preview. Therefore, the following options should be considered experimental and are subject to change:

  • :encrypted_fields_map and :bypass_query_analysis in auto encryption options.

  • :contention_factor and :query_type in client encryption options.

The following examples assume you are familiar with the concepts and techniques described in Client-Side Encryption.

Below is an example of using automatic queryable encryption using the Ruby driver:

require 'mongo'
#####################################
# Step 1: Create a local master key #
#####################################
# A local master key is a 96-byte binary blob.
local_master_key = SecureRandom.random_bytes(96)
# => "\xB2\xBE\x8EN\xD4\x14\xC2\x13\xC3..."
#############################
# Step 2: Create a data key #
#############################
kms_providers = {
local: {
key: local_master_key
}
}
# The key vault client is a Mongo::Client instance
# that will be used to store your data keys.
key_vault_client = Mongo::Client.new('mongodb://localhost:27017,localhost:27018')
# Use an instance of Mongo::ClientEncryption to create a new data key
client_encryption = Mongo::ClientEncryption.new(
key_vault_client,
key_vault_namespace: 'encryption.__keyVault',
kms_providers: kms_providers
)
data_key_id = client_encryption.create_data_key('local')
# => <BSON::Binary... type=ciphertext...>
#######################################################
# Step 3: Configure Mongo::Client for auto-encryption #
#######################################################
# Create an encrypted fields map, which tells the Mongo::Client which fields to encrypt.
encrypted_fields_map = {
'encryption_db.encryption_coll' => {
fields: [
{
path: 'encrypted_field',
bsonType: 'string',
keyId: data_key_id,
queries: {
queryType: 'equality'
}
}
]
}
}
# Configure the client for automatic encryption
client = Mongo::Client.new(
'mongodb://localhost:27017,localhost:27018',
auto_encryption_options: {
key_vault_namespace: 'encryption.__keyVault',
kms_providers: kms_providers,
encrypted_fields_map: encrypted_fields_map,
},
database: 'encryption_db'
)
# Make sure there is no data in the collection.
client.database.drop
# Create encrypted collection explicitly.
collection = client['encryption_coll'].create
# The string "sensitive data" will be encrypted and stored in the database
# as ciphertext
collection.insert_one(encrypted_field: 'sensitive data')
# The data is decrypted before being returned to the user
collection.find(encrypted_field: 'sensitive data').first['encrypted_field']
# => "sensitive data"
# A client with no auto_encryption_options is unable to decrypt the data
client_no_encryption = Mongo::Client.new(['localhost:27017'], database: 'encryption_db')
client_no_encryption['encryption_coll'].find.first['encrypted_field']
# => <BSON::Binary... type=ciphertext...>

The example above demonstrates using automatic encryption with a local master key. For more information about using other key management services to create a master key and create data keys, see the following sections of the Client-Side Encryption tutorial:

Below is an example of explicit queryable encryption.

require 'mongo'
#####################################
# Step 1: Create a local master key #
#####################################
# A local master key is a 96-byte binary blob.
local_master_key = SecureRandom.random_bytes(96)
# => "\xB2\xBE\x8EN\xD4\x14\xC2\x13\xC3..."
#############################
# Step 2: Create a data key #
#############################
kms_providers = {
local: {
key: local_master_key
}
}
# The key vault client is a Mongo::Client instance
# that will be used to store your data keys.
key_vault_client = Mongo::Client.new('mongodb://localhost:27017,localhost:27018')
# Use an instance of Mongo::ClientEncryption to create a new data key
client_encryption = Mongo::ClientEncryption.new(
key_vault_client,
key_vault_namespace: 'encryption.__keyVault',
kms_providers: kms_providers
)
data_key_id = client_encryption.create_data_key('local')
# => <BSON::Binary... type=ciphertext...>
##########################################
# Step 3: Create an encrypted collection #
##########################################
encrypted_fields = {
fields: [
{
path: 'encrypted_field',
bsonType: 'string',
keyId: data_key_id,
queries: {
queryType: 'equality',
contention: 0
}
}
]
}
# Create the client you will use to read and write the data to MongoDB
# Please note that to insert or query with an "Indexed" encrypted payload,
# you should use a ``Mongo::Client`` that is configured with ``:auto_encryption_options``.
# ``auto_encryption_options[:bypass_query_analysis]`` may be true.
# ``auto_encryption_options[:bypass_auto_encryption]`` must be not set or false.
client = Mongo::Client.new(
['localhost:27017'],
auto_encryption_options: {
key_vault_namespace: 'encryption.__keyVault',
kms_providers: kms_providers,
bypass_query_analysis: true,
},
database: 'encryption_db',
)
# Make sure there is no data in the collection.
client['encryption_coll'].drop(encrypted_fields: encrypted_fields)
# Create encrypted collection explicitly.
client['encryption_coll'].create(encrypted_fields: encrypted_fields)
#####################################################
# Step 4: Encrypt a string with explicit encryption #
#####################################################
# The value to encrypt
value = 'sensitive data'
# Encrypt the value
insert_payload = client_encryption.encrypt(
'sensitive data',
{
key_id: data_key_id,
algorithm: "Indexed",
contention_factor: 0
}
)
# Insert the encrypted value into the collection
client['encryption_coll'].insert_one(encrypted_field: insert_payload)
# Use the client to read the encrypted value from the database, then
# use the ClientEncryption object to decrypt it.
find_payload = client_encryption.encrypt(
'sensitive data',
{
key_id: data_key_id,
algorithm: "Indexed",
contention_factor: 0,
query_type: "equality"
}
)
find_result = client['encryption_coll'].find(encrypted_field: find_payload).first['encrypted_field']
# => 'sensitive data'
← In-Use Encryption