class Mongo::Crypt::AutoEncrypter
An AutoEcnrypter is an object that encapsulates the behavior of automatic encryption. It controls all resources associated with auto-encryption, including the libmongocrypt handle, key vault client object, mongocryptd client object, and encryption I/O.
The AutoEncrypter
is kept as an instance on a Mongo::Client
. Client
objects with the same auto_encryption_options Hash may share AutoEncrypters.
@api private
Constants
- DEFAULT_EXTRA_OPTIONS
A Hash of default values for the :extra_options option
Attributes
Public Class Methods
Set up encryption-related options and instance variables on the class that includes this module. Calls the same method on the Mongo::Crypt::Encrypter module.
@param [ Hash ] options
@option options [ Mongo::Client
] :client A client connected to the
encrypted collection.
@option options [ Mongo::Client
| nil ] :key_vault_client A client connected
to the MongoDB instance containing the encryption key vault; optional. If not provided, will default to :client option.
@option options [ String ] :key_vault_namespace The namespace of the key
vault in the format database.collection.
@option options [ Hash | nil ] :schema_map The JSONSchema of the collection(s)
with encrypted fields. This option is mutually exclusive with :schema_map_path.
@option options [ String | nil ] :schema_map_path A path to a file contains the JSON schema
of the collection that stores auto encrypted documents. This option is mutually exclusive with :schema_map.
@option options [ Boolean | nil ] :bypass_auto_encryption When true, disables
auto-encryption. Default is false.
@option options [ Hash | nil ] :extra_options Options
related to spawning
mongocryptd. These are set to default values if no option is passed in.
@option options [ Hash ] :kms_providers 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.
@option options [ Hash ] :kms_tls_options 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 Mongo::Client. @see Mongo::Client#initialize for list of TLS options.
@option options [ Hash | nil ] :encrypted_fields_map maps a collection
namespace to an encryptedFields. - Note: If a collection is present on both the encryptedFieldsMap and schemaMap, an error will be raised.
@option options [ Boolean | nil ] :bypass_query_analysis When true
disables automatic analysis of outgoing commands.
@option options [ String | nil ] :crypt_shared_lib_path Path that should
be the used to load the crypt shared library. Providing this option overrides default crypt shared library load paths for libmongocrypt.
@option options [ Boolean | nil ] :crypt_shared_lib_required Whether
crypt shared library is required. If 'true', an error will be raised if a crypt_shared library cannot be loaded by libmongocrypt.
@raise [ ArgumentError ] If required options are missing or incorrectly
formatted.
# File lib/mongo/crypt/auto_encrypter.rb, line 93 def initialize(options) Crypt.validate_ffi! # Note that this call may eventually, via other method invocations, # create additional clients which have to be cleaned up. @options = set_default_options(options).freeze @crypt_handle = Crypt::Handle.new( Crypt::KMS::Credentials.new(@options[:kms_providers]), Crypt::KMS::Validations.validate_tls_options(@options[:kms_tls_options]), schema_map: @options[:schema_map], schema_map_path: @options[:schema_map_path], encrypted_fields_map: @options[:encrypted_fields_map], bypass_query_analysis: @options[:bypass_query_analysis], crypt_shared_lib_path: @options[:extra_options][:crypt_shared_lib_path], crypt_shared_lib_required: @options[:extra_options][:crypt_shared_lib_required], ) @mongocryptd_options = @options[:extra_options].slice( :mongocryptd_uri, :mongocryptd_bypass_spawn, :mongocryptd_spawn_path, :mongocryptd_spawn_args ) @mongocryptd_options[:mongocryptd_bypass_spawn] = @options[:bypass_auto_encryption] || @options[:extra_options][:mongocryptd_bypass_spawn] || @crypt_handle.crypt_shared_lib_available? || @options[:extra_options][:crypt_shared_lib_required] unless @options[:extra_options][:crypt_shared_lib_required] || @crypt_handle.crypt_shared_lib_available? || @options[:bypass_query_analysis] # Set server selection timeout to 1 to prevent the client waiting for a # long timeout before spawning mongocryptd @mongocryptd_client = Client.new( @options[:extra_options][:mongocryptd_uri], monitoring_io: @options[:client].options[:monitoring_io], populator_io: @options[:client].options[:populator_io], server_selection_timeout: 10, database: @options[:client].options[:database] ) end begin @encryption_io = EncryptionIO.new( client: @options[:client], mongocryptd_client: @mongocryptd_client, key_vault_namespace: @options[:key_vault_namespace], key_vault_client: @key_vault_client, metadata_client: @metadata_client, mongocryptd_options: @mongocryptd_options ) rescue begin @mongocryptd_client&.close rescue => e log_warn("Error closing mongocryptd client in auto encrypter's constructor: #{e.class}: #{e}") # Drop this exception so that the original exception is raised end raise end rescue if @key_vault_client && @key_vault_client != options[:client] && @key_vault_client.cluster != options[:client].cluster then begin @key_vault_client.close rescue => e log_warn("Error closing key vault client in auto encrypter's constructor: #{e.class}: #{e}") # Drop this exception so that the original exception is raised end end if @metadata_client && @metadata_client != options[:client] && @metadata_client.cluster != options[:client].cluster then begin @metadata_client.close rescue => e log_warn("Error closing metadata client in auto encrypter's constructor: #{e.class}: #{e}") # Drop this exception so that the original exception is raised end end raise end
Public Instance Methods
Close the resources created by the AutoEncrypter
.
@return [ true ] Always true.
# File lib/mongo/crypt/auto_encrypter.rb, line 217 def close @mongocryptd_client.close if @mongocryptd_client if @key_vault_client && @key_vault_client != options[:client] && @key_vault_client.cluster != options[:client].cluster then @key_vault_client.close end if @metadata_client && @metadata_client != options[:client] && @metadata_client.cluster != options[:client].cluster then @metadata_client.close end true end
Decrypt a database command.
@param [ Hash ] command The command with encrypted fields.
@return [ BSON::Document ] The decrypted command.
# File lib/mongo/crypt/auto_encrypter.rb, line 206 def decrypt(command) AutoDecryptionContext.new( @crypt_handle, @encryption_io, command ).run_state_machine end
Encrypt a database command.
@param [ String ] database_name The name of the database on which the
command is being run.
@param [ Hash ] command The command to be encrypted.
@return [ BSON::Document ] The encrypted command.
# File lib/mongo/crypt/auto_encrypter.rb, line 192 def encrypt(database_name, command) AutoEncryptionContext.new( @crypt_handle, @encryption_io, database_name, command ).run_state_machine end
Whether this encrypter should perform encryption (returns false if the :bypass_auto_encryption option is set to true).
@return [ Boolean ] Whether to perform encryption.
# File lib/mongo/crypt/auto_encrypter.rb, line 181 def encrypt? !@options[:bypass_auto_encryption] end
Private Instance Methods
Creates or return already created internal client to be used for auto encryption.
@param [ Mongo::Client
] client A client connected to the
encrypted collection.
@return [ Mongo::Client
] Client
to be used as internal client for auto encryption.
# File lib/mongo/crypt/auto_encrypter.rb, line 297 def internal_client(client) @internal_client ||= client.with( auto_encryption_options: nil, min_pool_size: 0, monitoring: client.send(:monitoring), ) end
Returns a new set of options with the following changes:
-
sets default values for all extra_options
-
adds –idleShtudownTimeoutSecs=60 to extra_options if not already present
-
sets bypass_auto_encryption to false
-
sets default key vault client
# File lib/mongo/crypt/auto_encrypter.rb, line 243 def set_default_options(options) opts = options.dup extra_options = opts.delete(:extra_options) || Options::Redacted.new extra_options = DEFAULT_EXTRA_OPTIONS.merge(extra_options) has_timeout_string_arg = extra_options[:mongocryptd_spawn_args].any? do |elem| elem.is_a?(String) && elem.match(/\A--idleShutdownTimeoutSecs=\d+\z/) end timeout_int_arg_idx = extra_options[:mongocryptd_spawn_args].index('--idleShutdownTimeoutSecs') has_timeout_int_arg = timeout_int_arg_idx && extra_options[:mongocryptd_spawn_args][timeout_int_arg_idx + 1].is_a?(Integer) unless has_timeout_string_arg || has_timeout_int_arg extra_options[:mongocryptd_spawn_args] << '--idleShutdownTimeoutSecs=60' end opts[:bypass_auto_encryption] ||= false set_or_create_clients(opts) opts[:key_vault_client] = @key_vault_client Options::Redacted.new(opts).merge(extra_options: extra_options) end
Create additional clients for auto encryption, if necessary
@param [ Hash ] options Auto encryption options.
# File lib/mongo/crypt/auto_encrypter.rb, line 270 def set_or_create_clients(options) client = options[:client] @key_vault_client = if options[:key_vault_client] options[:key_vault_client] elsif client.options[:max_pool_size] == 0 client else internal_client(client) end @metadata_client = if options[:bypass_auto_encryption] nil elsif client.options[:max_pool_size] == 0 client else internal_client(client) end end