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'