Skip to content

Commit 28b3713

Browse files
comandeo-mongop
andauthored
RUBY-2986 Add queryable encryption docs (#2522)
Co-authored-by: Oleg Pudeyev <[email protected]>
1 parent f866633 commit 28b3713

File tree

5 files changed

+350
-9
lines changed

5 files changed

+350
-9
lines changed

docs/reference/client-side-encryption.txt

Lines changed: 234 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,11 @@ in order to perform automatic encryption.
204204
key_vault_namespace: 'encryption.__keyVault',
205205
kms_providers: kms_providers,
206206
schema_map: schema_map
207-
}
207+
},
208+
database: 'encryption_db',
208209
)
209210

210-
collection = client.use('encryption_db')['encryption_coll']
211+
collection = client['encryption_coll']
211212
collection.drop # Make sure there is no data in the collection
212213

213214
# The string "sensitive data" will be encrypted and stored in the database
@@ -219,8 +220,11 @@ in order to perform automatic encryption.
219220
# => "sensitive data"
220221

221222
# A client with no auto_encryption_options is unable to decrypt the data
222-
client_no_encryption = Mongo::Client.new(['localhost:27017'])
223-
client_no_encryption.use('encryption_db')['encryption_coll'].find.first['encrypted_field']
223+
client_no_encryption = Mongo::Client.new(
224+
['localhost:27017'],
225+
database: 'encryption_db',
226+
)
227+
client_no_encryption.['encryption_coll'].find.first['encrypted_field']
224228
# => <BSON::Binary... type=ciphertext...>
225229

226230
The example above demonstrates using automatic encryption with a local master key.
@@ -232,6 +236,7 @@ master key and create data keys, see the following sections of this tutorial:
232236

233237
Explicit Encryption
234238
===================
239+
235240
Explicit encryption is a feature that allows users to encrypt and decrypt
236241
individual pieces of data such as strings, integers, or symbols. Explicit
237242
encryption is a community feature and does not require an enterprise build
@@ -302,8 +307,11 @@ in order to perform explicit encryption.
302307
)
303308

304309
# Create the client you will use to read and write the data to MongoDB
305-
client = Mongo::Client.new(['localhost:27017'])
306-
collection = client.use('encryption_db')['encryption_coll']
310+
client = Mongo::Client.new(
311+
['localhost:27017'],
312+
database: 'encryption_db',
313+
)
314+
collection = client['encryption_coll']
307315
collection.drop # Make sure there is no data in the collection
308316

309317
# Insert the encrypted value into the collection
@@ -324,6 +332,215 @@ master key and create data keys, see the following sections of this tutorial:
324332
- `Creating A Master Key`_,
325333
- `Creating A Data Key`_,
326334

335+
Queryable Encryption
336+
====================
337+
338+
Queryable encryption is a new feature in MongoDB 6.0. It also requires
339+
libmongocrypt version 1.5.0-rc1 or above.
340+
341+
You can find more information about queryable encryption in `MongoDB Manual
342+
<https://www.mongodb.com/docs/upcoming/core/queryable-encryption/queryable-encryption/>`_
343+
344+
.. note::
345+
346+
The queryable encryption feature is in public technical preview.
347+
Therefore, the following options should be considered experimental
348+
and are subject to change:
349+
350+
- ``:encrypted_fields_map`` and ``:bypass_query_analysis`` in auto encryption options.
351+
- ``:contention_factor`` and ``:query_type`` in client encryption options.
352+
353+
Below is an example of using automatic queryable encryption using the Ruby driver:
354+
355+
.. code-block:: ruby
356+
357+
require 'mongo'
358+
359+
#####################################
360+
# Step 1: Create a local master key #
361+
#####################################
362+
363+
# A local master key is a 96-byte binary blob.
364+
local_master_key = SecureRandom.random_bytes(96)
365+
# => "\xB2\xBE\x8EN\xD4\x14\xC2\x13\xC3..."
366+
367+
#############################
368+
# Step 2: Create a data key #
369+
#############################
370+
371+
kms_providers = {
372+
local: {
373+
key: local_master_key
374+
}
375+
}
376+
377+
# The key vault client is a Mongo::Client instance
378+
# that will be used to store your data keys.
379+
key_vault_client = Mongo::Client.new(['localhost:27017'])
380+
381+
# Use an instance of Mongo::ClientEncryption to create a new data key
382+
client_encryption = Mongo::ClientEncryption.new(
383+
key_vault_client,
384+
key_vault_namespace: 'encryption.__keyVault',
385+
kms_providers: kms_providers
386+
)
387+
388+
data_key_id = client_encryption.create_data_key('local')
389+
# => <BSON::Binary... type=ciphertext...>
390+
391+
#######################################################
392+
# Step 3: Configure Mongo::Client for auto-encryption #
393+
#######################################################
394+
395+
# Create an encrypted fields map, which tells the Mongo::Client which fields to encrypt.
396+
encrypted_fields_map = {
397+
'encryption_db.encryption_coll' => {
398+
fields: [
399+
{
400+
path: 'encrypted_field',
401+
bsonType: 'string',
402+
keyId: data_key_id,
403+
queries: {
404+
queryType: 'equality'
405+
}
406+
}
407+
]
408+
}
409+
}
410+
411+
# Configure the client for automatic encryption
412+
client = Mongo::Client.new(
413+
['localhost:27017'],
414+
auto_encryption_options: {
415+
key_vault_namespace: 'encryption.__keyVault',
416+
kms_providers: kms_providers,
417+
encrypted_fields_map: encrypted_fields_map,
418+
},
419+
database: 'encryption_db'
420+
)
421+
422+
# Make sure there is no data in the collection.
423+
client.database.drop
424+
425+
# Create encrypted collection explicitly.
426+
collection = client['encryption_coll'].create
427+
428+
# The string "sensitive data" will be encrypted and stored in the database
429+
# as ciphertext
430+
collection.insert_one(encrypted_field: 'sensitive data')
431+
432+
# The data is decrypted before being returned to the user
433+
collection.find(encrypted_field: 'sensitive data').first['encrypted_field']
434+
# => "sensitive data"
435+
436+
# A client with no auto_encryption_options is unable to decrypt the data
437+
client_no_encryption = Mongo::Client.new(['localhost:27017'], database: 'encryption_db')
438+
client_no_encryption['encryption_coll'].find.first['encrypted_field']
439+
# => <BSON::Binary... type=ciphertext...>
440+
441+
The example above demonstrates using automatic encryption with a local master key.
442+
For more information about using other key management services to create a
443+
master key and create data keys, see the following sections of this tutorial:
444+
445+
- `Creating A Master Key`_
446+
- `Creating A Data Key`_
447+
448+
Below is an example of explicit queryable encryption.
449+
450+
.. code-block:: ruby
451+
452+
require 'mongo'
453+
454+
#####################################
455+
# Step 1: Create a local master key #
456+
#####################################
457+
458+
# A local master key is a 96-byte binary blob.
459+
local_master_key = SecureRandom.random_bytes(96)
460+
# => "\xB2\xBE\x8EN\xD4\x14\xC2\x13\xC3..."
461+
462+
#############################
463+
# Step 2: Create a data key #
464+
#############################
465+
466+
kms_providers = {
467+
local: {
468+
key: local_master_key
469+
}
470+
}
471+
472+
# The key vault client is a Mongo::Client instance
473+
# that will be used to store your data keys.
474+
key_vault_client = Mongo::Client.new(['localhost:27017'])
475+
476+
# Use an instance of Mongo::ClientEncryption to create a new data key
477+
client_encryption = Mongo::ClientEncryption.new(
478+
key_vault_client,
479+
key_vault_namespace: 'encryption.__keyVault',
480+
kms_providers: kms_providers
481+
)
482+
483+
data_key_id = client_encryption.create_data_key('local')
484+
# => <BSON::Binary... type=ciphertext...>
485+
486+
##########################################
487+
# Step 3: Create an encrypted collection #
488+
##########################################
489+
490+
# Create the client you will use to read and write the data to MongoDB
491+
client = Mongo::Client.new(['localhost:27017'], database: 'encryption_db')
492+
493+
encrypted_fields = {
494+
fields: [
495+
{
496+
path: 'encrypted_field',
497+
bsonType: 'string',
498+
keyId: data_key_id,
499+
queries: {
500+
queryType: 'equality'
501+
}
502+
}
503+
]
504+
}
505+
506+
# Make sure there is no data in the collection.
507+
client['encryption_coll'].drop(encrypted_field: encrypted_fields)
508+
# Create encrypted collection explicitly.
509+
collection = client['encryption_coll'].create(encrypted_fields: encrypted_fields)
510+
511+
#####################################################
512+
# Step 4: Encrypt a string with explicit encryption #
513+
#####################################################
514+
515+
# The value to encrypt
516+
value = 'sensitive data'
517+
518+
# Encrypt the value
519+
insert_payload = client_encryption.encrypt(
520+
'sensitive data',
521+
{
522+
key_id: data_key_id,
523+
algorithm: "Indexed"
524+
}
525+
)
526+
527+
# Insert the encrypted value into the collection
528+
collection.insert_one(encrypted_field: insert_payload)
529+
530+
# Use the client to read the encrypted value from the database, then
531+
# use the ClientEncryption object to decrypt it
532+
find_payload = client_encryption.encrypt(
533+
'sensitive data',
534+
{
535+
key_id: data_key_id,
536+
algorithm: "Indexed",
537+
query_type: :equality
538+
}
539+
)
540+
find_result = collection.find(encrypted_field: find_payload).first['encrypted_field']
541+
# => 'sensitive data'
542+
543+
327544
Creating a Master Key
328545
=====================
329546
Both automatic encryption and explicit encryption require an encryption master key.
@@ -335,6 +552,7 @@ Google Cloud Key Management (GCP KMS).
335552

336553
Local Master Key
337554
~~~~~~~~~~~~~~~~
555+
338556
A local master key is a 96-byte binary string. It should be persisted
339557
on your machine as an environment variable or in a text file.
340558

@@ -363,6 +581,7 @@ section of the MongoDB manual.
363581

364582
Creating a Data Key
365583
===================
584+
366585
Once you have created a master key, create a data key by calling the
367586
``#create_data_key`` method on an instance of the ``Mongo::ClientEncryption``
368587
class. This method generates a new data key and inserts it into the key vault
@@ -434,7 +653,6 @@ and key id. You will use that information to generate a data key. You may also
434653
need certificate authority certificate(s), as well as and your client
435654
certificate and private key to authenticate to KMIP server.
436655

437-
438656
.. code-block:: ruby
439657

440658
# A Mongo::Client instance that will be used to connect to the key vault
@@ -527,13 +745,15 @@ see :manual:`create client reference </reference/config-database/>`.
527745

528746
Auto-Encryption Options
529747
=======================
748+
530749
Automatic encryption can be configured on a ``Mongo::Client`` using the
531750
``auto_encryption_options`` option ``Hash``. This section provides an overview
532751
of the fields inside ``auto_encryption_options`` and explains how to choose their
533752
values.
534753

535754
``:key_vault_client``
536755
~~~~~~~~~~~~~~~~~~~~~
756+
537757
The key vault client is a ``Mongo::Client`` instance that will be used to connect
538758
to the MongoDB collection containing your encryption data keys. For example, if
539759
your key vault was hosted on a MongoDB instance at ``localhost:30000``:
@@ -555,6 +775,7 @@ to insert and fetch data keys.
555775

556776
``:key_vault_namespace``
557777
~~~~~~~~~~~~~~~~~~~~~~~~
778+
558779
The key vault namespace is a ``String`` in the format ``"database_name.collection_name"``,
559780
where ``database_name`` and ``collection_name`` are the name of the database and
560781
collection in which you would like to store your data keys. For example, if your data
@@ -573,6 +794,7 @@ There is no default key vault namespace, and this option must be provided.
573794

574795
``:kms_providers``
575796
~~~~~~~~~~~~~~~~~~
797+
576798
A Hash that contains KMP provider names as keys, and provider options as values.
577799

578800
.. code-block:: ruby
@@ -590,7 +812,8 @@ A Hash that contains KMP provider names as keys, and provider options as values.
590812
)
591813

592814
``:kms_tls_options``
593-
~~~~~~~~~~~~~~~~~~
815+
~~~~~~~~~~~~~~~~~~~~
816+
594817
A Hash that contains KMP provider names as keys, and TLS options to connect to
595818
corresponding providers.
596819

@@ -617,6 +840,7 @@ corresponding providers.
617840

618841
``:schema_map``
619842
~~~~~~~~~~~~~~~
843+
620844
A schema map is a Hash with information about which fields to automatically
621845
encrypt and decrypt.
622846

@@ -697,6 +921,7 @@ When you intend to use your schema map, convert it to a Ruby ``Hash`` using the
697921

698922
``:bypass_auto_encryption``
699923
~~~~~~~~~~~~~~~~~~~~~~~~~~~
924+
700925
The ``:bypass_auto_encryption`` option is a ``Boolean`` that specifies whether the
701926
``Mongo::Client`` should skip encryption when writing to the database. If
702927
``:bypass_auto_encryption`` is ``true``, the client will still perform automatic
@@ -713,6 +938,7 @@ decryption of any previously-encrypted data.
713938

714939
``:extra_options``
715940
~~~~~~~~~~~~~~~~~~
941+
716942
``:extra_options`` is a ``Hash`` of options related to spawning mongocryptd.
717943
Every option in this ``Hash`` has a default value, so it is only necessary to
718944
provide the options whose defaults you want to override.

docs/release-notes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This release of the Ruby driver supports MongoDB version 5.2.
2424

2525
This release includes the following new features:
2626

27+
- Added support for queryable encryption.
2728
- Added support for Azure Key Vault, Google Cloud Key Management, and any
2829
KMIP compliant Key Management System to be used as master key storage for
2930
client side encryption.

spec/integration/client_side_encryption/explicit_queryable_encryption_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
describe 'Explicit Queryable Encryption' do
77
require_libmongocrypt
8-
min_server_version '6.0'
8+
min_server_version '6.0.0-rc8'
99
require_topology :replica_set, :sharded, :load_balanced
1010

1111
include_context 'define shared FLE helpers'

0 commit comments

Comments
 (0)