123456789_123456789_123456789_123456789_123456789_

Class: Mongo::ClientEncryption

Relationships & Source Files
Inherits: Object
Defined in: lib/mongo/client_encryption.rb

Overview

ClientEncryption encapsulates explicit operations on a key vault collection that cannot be done directly on a MongoClient. It provides an API for explicitly encrypting and decrypting values, and creating data keys.

Class Method Summary

Instance Method Summary

Constructor Details

.new(key_vault_client, options = {}) ⇒ ClientEncryption

Create a new ClientEncryption object with the provided options.

Parameters:

  • key_vault_client (Mongo::Client)

    A Mongo::Client that is connected to the MongoDB instance where the key vault collection is stored.

  • options (Hash) (defaults to: {})

    The ClientEncryption options.

Options Hash (options):

  • :key_vault_namespace (String)

    The name of the key vault collection in the format “database.collection”.

  • :kms_providers (Hash)

    A hash of key management service configuration information. @see Mongo::Crypt::KMS::Credentials for list of options for every supported provider. @note There may be more than one KMS provider specified.

  • :kms_tls_options (Hash)

    TLS options to connect to KMS providers. Keys of the hash should be KSM provider names; values should be hashes of TLS connection options. The options are equivalent to TLS connection options of Client. @see Mongo::Client#initialize for list of TLS options.

  • :timeout_ms (Integer)

    The operation timeout in milliseconds. Must be a non-negative integer. An explicit value of 0 means infinite. The default value is unset which means the feature is disabled.

Raises:

  • (ArgumentError)

    If required options are missing or incorrectly formatted.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 49

def initialize(key_vault_client, options = {})
  @encrypter = Crypt::ExplicitEncrypter.new(
    key_vault_client,
    options[:key_vault_namespace],
    Crypt::KMS::Credentials.new(options[:kms_providers]),
    Crypt::KMS::Validations.validate_tls_options(options[:kms_tls_options])
  )
end

Instance Method Details

#add_key_alt_name(id, key_alt_name) ⇒ BSON::Document | nil

Adds a key_alt_name for the key in the key vault collection with the given id.

Parameters:

  • id (BSON::Binary)

    Id of the key to add new key alt name.

  • key_alt_name (String)

    New key alt name to add.

Returns:

  • (BSON::Document | nil)

    Document describing the identified key before adding the key alt name, or nil if no such key.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 183

def add_key_alt_name(id, key_alt_name)
  @encrypter.add_key_alt_name(id, key_alt_name)
end

#create_data_key(kms_provider, options = {}) ⇒ BSON::Binary

Generates a data key used for encryption/decryption and stores that key in the KMS collection. The generated key is encrypted with the KMS master key.

Parameters:

  • kms_provider (String)

    The KMS provider to use. Valid values are “aws” and “local”.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :master_key (Hash)

    Information about the AWS master key. Required if kms_provider is “aws”.

    • :region [ String ] The The AWS region of the master key (required).

    • :key [ String ] The Amazon Resource Name (ARN) of the master key (required).

    • :endpoint [ String ] An alternate host to send KMS requests to (optional). endpoint should be a host name with an optional port number separated by a colon (e.g. “kms.us-east-1.amazonaws.com” or “kms.us-east-1.amazonaws.com:443”). An endpoint in any other format will not be properly parsed.

  • :key_alt_names (Array<String>)

    An optional array of strings specifying alternate names for the new data key.

  • :key_material (String | nil)

    Optional 96 bytes to use as custom key material for the data key being created. If :key_material option is given, the custom key material is used for encrypting and decrypting data.

Returns:

  • (BSON::Binary)

    The 16-byte UUID of the new data key as a BSON::Binary object with type :uuid.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 84

def create_data_key(kms_provider, options={})
  key_document = Crypt::KMS::MasterKeyDocument.new(kms_provider, options)

  key_alt_names = options[:key_alt_names]
  key_material = options[:key_material]
  @encrypter.create_and_insert_data_key(key_document, key_alt_names, key_material)
end

#create_data_keys(encrypted_fields, kms_provider, master_key) ⇒ Hash (private)

Create data keys for fields in encrypted_fields that has :keyId key, but the value is nil.

Parameters:

  • encrypted_fields (Hash)

    Encrypted fields map.

  • kms_provider (String)

    KMS provider to encrypt fields.

  • master_key (Hash | nil)

    Document describing master key to encrypt fields.

Returns:

  • (Hash)

    Encrypted fields map with keyIds for fields that did not have one.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 294

def create_data_keys(encrypted_fields, kms_provider, master_key)
  encrypted_fields = encrypted_fields.dup
  # We must return the partially formed encrypted_fields hash if an error
  # occurs - https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.md#create-encrypted-collection-helper
  # Thefore, we do this in a loop instead of using #map.
  encrypted_fields[:fields].size.times do |i|
    field = encrypted_fields[:fields][i]
    next unless field.is_a?(Hash) && field.fetch(:keyId, false).nil?

    begin
      encrypted_fields[:fields][i][:keyId] = create_data_key(kms_provider, master_key: master_key)
    rescue Error::CryptError => e
      raise Error::CryptError, "Error creating data key for field #{field[:path]} \
          with encrypted fields #{encrypted_fields}: #{e.class}: #{e.message}"
    end
  end
  encrypted_fields
end

#create_encrypted_collection(database, coll_name, coll_opts, kms_provider, master_key) ⇒ Array<Operation::Result, Hash>

Note:

This method does not update the :encrypted_fields_map in the client’s :auto_encryption_options. Therefore, in order to use the collection created by this method with automatic encryption, the user must create a new client after calling this function with the :encrypted_fields returned.

Create collection with encrypted fields.

If :encryption_fields contains a keyId with a null value, a data key will be automatically generated and assigned to keyId value.

Parameters:

  • database (Mongo::Database)

    Database to create collection in.

  • coll_name (String)

    Name of collection to create.

  • coll_opts (Hash)

    Options for collection to create.

  • kms_provider (String)

    KMS provider to encrypt fields.

  • master_key (Hash | nil)

    Document describing master key to encrypt fields.

Returns:

  • (Array<Operation::Result, Hash>)

    The result of the create collection operation and the encrypted fields map used to create the collection.

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 270

def create_encrypted_collection(database, coll_name, coll_opts, kms_provider, master_key)
  raise ArgumentError, 'coll_opts must contain :encrypted_fields' unless coll_opts[:encrypted_fields]

  encrypted_fields = create_data_keys(coll_opts[:encrypted_fields], kms_provider, master_key)
  begin
    new_coll_opts = coll_opts.dup.merge(encrypted_fields: encrypted_fields)
    [database[coll_name].create(new_coll_opts), encrypted_fields]
  rescue Mongo::Error => e
    raise Error::CryptError, "Error creating collection with encrypted fields \
          #{encrypted_fields}: #{e.class}: #{e.message}"
  end
end

#decrypt(value) ⇒ Object

Decrypts a value that has already been encrypted.

Parameters:

  • value (BSON::Binary)

    A BSON Binary object of subtype 6 (ciphertext) that will be decrypted.

Returns:

  • (Object)

    The decrypted value.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 172

def decrypt(value)
  @encrypter.decrypt(value)
end

#delete_key(id) ⇒ Operation::Result

Removes the key with the given id from the key vault collection.

Parameters:

  • id (BSON::Binary)

    Id of the key to delete.

Returns:

  • (Operation::Result)

    The response from the database for the delete_one operation that deletes the key.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 193

def delete_key(id)
  @encrypter.delete_key(id)
end

#encrypt(value, options = {}) ⇒ BSON::Binary

Note:

The :key_id and :key_alt_name options are mutually exclusive. Only one is required to perform explicit encryption.

Encrypts a value using the specified encryption key and algorithm.

if encryption algorithm is set to “Indexed”. Query type should be set

only if encryption algorithm is set to "Indexed". The only allowed
value is "equality".

Parameters:

  • value (Object)

    The value to encrypt.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :key_id (BSON::Binary)

    A BSON::Binary object of type :uuid representing the UUID of the encryption key as it is stored in the key vault collection.

  • :key_alt_name (String)

    The alternate name for the encryption key.

  • :algorithm (String)

    The algorithm used to encrypt the value. Valid algorithms are “AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic”, “AEAD_AES_256_CBC_HMAC_SHA_512-Random”, “Indexed”, “Unindexed”.

  • :contention_factor (Integer | nil)

    Contention factor to be applied if encryption algorithm is set to “Indexed”. If not provided, it defaults to a value of 0. Contention factor should be set only if encryption algorithm is set to “Indexed”.

  • query_type (String | nil)

    Query type to be applied

Returns:

  • (BSON::Binary)

    A BSON Binary object of subtype 6 (ciphertext) representing the encrypted value.

Raises:

  • (ArgumentError)

    if either contention_factor or query_type is set, and algorithm is not “Indexed”.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 122

def encrypt(value, options={})
  @encrypter.encrypt(value, options)
end

#encrypt_expression(expression, options = {}) ⇒ BSON::Binary

Note:

The :key_id and :key_alt_name options are mutually exclusive. Only one is required to perform explicit encryption.

Encrypts a Match Expression or Aggregate Expression to query a range index.

Only supported when queryType is “range” and algorithm is “Range”. @note: The Range algorithm is experimental only. It is not intended

for public use. It is subject to breaking changes.

@param [ Hash ] options

Examples:

Encrypt Match Expression.

encryption.encrypt_expression(
  {'$and' =>  [{'field' => {'$gt' => 10}}, {'field' =>  {'$lt' => 20 }}]}
)

Encrypt Aggregate Expression.

encryption.encrypt_expression(
  {'$and' =>  [{'$gt' => ['$field', 10]}, {'$lt' => ['$field', 20]}}
)
{$and: [{$gt: [<fieldpath>, <value1>]}, {$lt: [<fieldpath>, <value2>]}]

Parameters:

  • expression (Hash)

    Expression to encrypt.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :key_id (BSON::Binary)

    A BSON::Binary object of type :uuid representing the UUID of the encryption key as it is stored in the key vault collection.

  • :key_alt_name (String)

    The alternate name for the encryption key.

  • :algorithm (String)

    The algorithm used to encrypt the expression. The only allowed value is “Range”

  • :contention_factor (Integer | nil)

    Contention factor to be applied If not provided, it defaults to a value of 0.

  • query_type (String | nil)

    Query type to be applied. The only allowed value is “range”.

Returns:

  • (BSON::Binary)

    A BSON Binary object of subtype 6 (ciphertext) representing the encrypted expression.

Raises:

  • (ArgumentError)

    if disallowed values in options are set.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 162

def encrypt_expression(expression, options = {})
  @encrypter.encrypt_expression(expression, options)
end

#get_key(id) ⇒ BSON::Document | nil

Finds a single key with the given id.

Parameters:

  • id (BSON::Binary)

    Id of the key to get.

Returns:

  • (BSON::Document | nil)

    The found key document or nil if not found.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 203

def get_key(id)
  @encrypter.get_key(id)
end

#get_key_by_alt_name(key_alt_name) ⇒ BSON::Document | nil

Returns a key in the key vault collection with the given key_alt_name.

Parameters:

  • key_alt_name (String)

    Key alt name to find a key.

Returns:

  • (BSON::Document | nil)

    The found key document or nil if not found.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 213

def get_key_by_alt_name(key_alt_name)
  @encrypter.get_key_by_alt_name(key_alt_name)
end

#get_keysCollection::View Also known as: #keys

Returns all keys in the key vault collection.

Returns:

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 220

def get_keys
  @encrypter.get_keys
end

#keys

Alias for #get_keys.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 223

alias :keys :get_keys

#remove_key_alt_name(id, key_alt_name) ⇒ BSON::Document | nil

Removes a key_alt_name from a key in the key vault collection with the given id.

Parameters:

  • id (BSON::Binary)

    Id of the key to remove key alt name.

  • key_alt_name (String)

    Key alt name to remove.

Returns:

  • (BSON::Document | nil)

    Document describing the identified key before removing the key alt name, or nil if no such key.

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 232

def remove_key_alt_name(id, key_alt_name)
  @encrypter.remove_key_alt_name(id, key_alt_name)
end

#rewrap_many_data_key(filter, opts = {}) ⇒ Crypt::RewrapManyDataKeyResult

Decrypts multiple data keys and (re-)encrypts them with a new master_key,

or with their current master_key if a new one is not given.

Parameters:

  • filter (Hash)

    Filter used to find keys to be updated.

  • options (Hash)

Returns:

[ GitHub ]

  
# File 'lib/mongo/client_encryption.rb', line 247

def rewrap_many_data_key(filter, opts = {})
  @encrypter.rewrap_many_data_key(filter, opts)
end