class Aws::S3::EncryptionV2::Client

Attributes

client[R]

@return [S3::Client]

envelope_location[R]

@return [Symbol<:metadata, :instruction_file>]

instruction_file_suffix[R]

@return [String] When {#envelope_location} is `:instruction_file`,

the envelope is stored in the object with the object key suffixed
by this string.
key_provider[R]

@return [KeyProvider, nil] Returns `nil` if you are using

AWS Key Management Service (KMS).
kms_allow_decrypt_with_any_cmk[R]

@return [Boolean] If true the provided KMS key_id will not be used

during decrypt, allowing decryption with the key_id from the object.
security_profile[R]

@return [Symbol] Determines the support for reading objects written

using older key wrap or content encryption schemas.

Public Class Methods

new(options = {}) click to toggle source

Creates a new encryption client. You must configure all of the following:

  • a key or key provider - The key provided also determines the key wrapping schema(s) supported for both encryption and decryption.

  • `key_wrap_schema` - The key wrapping schema. It must match the type of key configured.

  • `content_encryption_schema` - The only supported value currently is `:aes_gcm_no_padding`

    More options will be added in future releases.
  • `security_profile` - Determines the support for reading objects written

    using older key wrap or content encryption schemas. If you need to read
    legacy objects encrypted by an existing V1 Client, then set this to `:v2_and_legacy`.
    Otherwise, set it to `:v2`

To configure the key you must provide one of the following set of options:

  • `:encryption_key`

  • `:kms_key_id`

  • `:key_provider`

You may also pass any other options accepted by `Client#initialize`.

@option options [S3::Client] :client A basic S3 client that is used

to make api calls. If a `:client` is not provided, a new {S3::Client}
will be constructed.

@option options [OpenSSL::PKey::RSA, String] :encryption_key The master

key to use for encrypting/decrypting all objects.

@option options [String] :kms_key_id When you provide a `:kms_key_id`,

then AWS Key Management Service (KMS) will be used to manage the
object encryption keys. By default a {KMS::Client} will be
constructed for KMS API calls. Alternatively, you can provide
your own via `:kms_client`. To only support decryption/reads, you may
provide `:allow_decrypt_with_any_cmk` which will use
the implicit CMK associated with the data during reads but will
not allow you to encrypt/write objects with this client.

@option options [#key_for] :key_provider Any object that responds

to `#key_for`. This method should accept a materials description
JSON document string and return return an encryption key.

@option options [required, Symbol] :key_wrap_schema The Key wrapping

schema to be used. It must match the type of key configured.
Must be one of the following:

* :kms_context  (Must provide kms_key_id)
* :aes_gcm (Must provide an AES (string) key)
* :rsa_oaep_sha1 (Must provide an RSA key)

@option options [required, Symbol] :content_encryption_schema

Must be one of the following:

* :aes_gcm_no_padding

@option options [Required, Symbol] :security_profile

Determines the support for reading objects written using older
key wrap or content encryption schemas.
Must be one of the following:

* :v2 - Reads of legacy (v1) objects are NOT allowed
* :v2_and_legacy - Enables reading of legacy (V1) schemas.

@option options [Symbol] :envelope_location (:metadata) Where to

store the envelope encryption keys. By default, the envelope is
stored with the encrypted object. If you pass `:instruction_file`,
then the envelope is stored in a separate object in Amazon S3.

@option options [String] :instruction_file_suffix ('.instruction')

When `:envelope_location` is `:instruction_file` then the
instruction file uses the object key with this suffix appended.

@option options [KMS::Client] :kms_client A default {KMS::Client}

is constructed when using KMS to manage encryption keys.
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 310
def initialize(options = {})
  validate_params(options)
  @client = extract_client(options)
  @cipher_provider = cipher_provider(options)
  @envelope_location = extract_location(options)
  @instruction_file_suffix = extract_suffix(options)
  @kms_allow_decrypt_with_any_cmk =
    options[:kms_key_id] == :kms_allow_decrypt_with_any_cmk
  @security_profile = extract_security_profile(options)
end

Public Instance Methods

get_object(params = {}, &block) click to toggle source

Gets an object from Amazon S3, decrypting data locally. See {S3::Client#get_object} for documentation on accepted request parameters. Warning: If you provide a block to get_object or set the request parameter :response_target to a Proc, then read the entire object to the end before you start using the decrypted data. This is to verify that the object has not been modified since it was encrypted.

@option options [Symbol] :security_profile

Determines the support for reading objects written using older
key wrap or content encryption schemas. Overrides the value set
on client construction if provided.
Must be one of the following:

* :v2 - Reads of legacy (v1) objects are NOT allowed
* :v2_and_legacy - Enables reading of legacy (V1) schemas.

@option params [String] :instruction_file_suffix The suffix

used to find the instruction file containing the encryption
envelope. You should not set this option when the envelope
is stored in the object metadata. Defaults to
{#instruction_file_suffix}.

@option params [Hash] :kms_encryption_context Additional encryption

context to use with KMS.  Applies only when KMS is used.

@option options [Boolean] :kms_allow_decrypt_with_any_cmk (false)

By default the KMS CMK ID (kms_key_id) will be used during decrypt
and will fail if there is a mismatch.  Setting this to true
will use the implicit CMK associated with the data.

@option (see S3::Client#get_object) @return (see S3::Client#get_object) @see S3::Client#get_object @note The `:range` request parameter is not supported.

# File lib/aws-sdk-s3/encryptionV2/client.rb, line 398
def get_object(params = {}, &block)
  if params[:range]
    raise NotImplementedError, '#get_object with :range not supported'
  end
  envelope_location, instruction_file_suffix = envelope_options(params)
  kms_encryption_context = params.delete(:kms_encryption_context)
  kms_any_cmk_mode = kms_any_cmk_mode(params)
  security_profile = security_profile_from_params(params)

  req = @client.build_request(:get_object, params)
  req.handlers.add(DecryptHandler)
  req.context[:encryption] = {
    cipher_provider: @cipher_provider,
    envelope_location: envelope_location,
    instruction_file_suffix: instruction_file_suffix,
    kms_encryption_context: kms_encryption_context,
    kms_allow_decrypt_with_any_cmk: kms_any_cmk_mode,
    security_profile: security_profile
  }
  req.send_request(target: block)
end
put_object(params = {}) click to toggle source

Uploads an object to Amazon S3, encrypting data client-side. See {S3::Client#put_object} for documentation on accepted request parameters. @option params [Hash] :kms_encryption_context Additional encryption

context to use with KMS.  Applies only when KMS is used. In order
to decrypt the object you will need to provide the identical
:kms_encryption_context to `get_object`.

@option (see S3::Client#put_object) @return (see S3::Client#put_object) @see S3::Client#put_object

# File lib/aws-sdk-s3/encryptionV2/client.rb, line 354
def put_object(params = {})
  kms_encryption_context = params.delete(:kms_encryption_context)
  req = @client.build_request(:put_object, params)
  req.handlers.add(EncryptHandler, priority: 95)
  req.context[:encryption] = {
    cipher_provider: @cipher_provider,
    envelope_location: @envelope_location,
    instruction_file_suffix: @instruction_file_suffix,
    kms_encryption_context: kms_encryption_context
  }
  req.send_request
end

Private Instance Methods

cipher_provider(options) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 465
def cipher_provider(options)
  if options[:kms_key_id]
    KmsCipherProvider.new(
      kms_key_id: options[:kms_key_id],
      kms_client: kms_client(options),
      key_wrap_schema: options[:key_wrap_schema],
      content_encryption_schema: options[:content_encryption_schema]
    )
  else
    @key_provider = extract_key_provider(options)
    DefaultCipherProvider.new(
      key_provider: @key_provider,
      key_wrap_schema: options[:key_wrap_schema],
      content_encryption_schema: options[:content_encryption_schema]
    )
  end
end
envelope_options(params) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 494
def envelope_options(params)
  location = params.delete(:envelope_location) || @envelope_location
  suffix = params.delete(:instruction_file_suffix)
  if suffix
    [:instruction_file, suffix]
  else
    [location, @instruction_file_suffix]
  end
end
extract_client(options) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 442
def extract_client(options)
  options[:client] || begin
    options = options.dup
    options.delete(:kms_key_id)
    options.delete(:kms_client)
    options.delete(:key_provider)
    options.delete(:encryption_key)
    options.delete(:envelope_location)
    options.delete(:instruction_file_suffix)
    REQUIRED_PARAMS.each { |p| options.delete(p) }
    S3::Client.new(options)
  end
end
extract_key_provider(options) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 483
def extract_key_provider(options)
  if options[:key_provider]
    options[:key_provider]
  elsif options[:encryption_key]
    DefaultKeyProvider.new(options)
  else
    msg = 'you must pass a :kms_key_id, :key_provider, or :encryption_key'
    raise ArgumentError, msg
  end
end
extract_location(options) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 504
def extract_location(options)
  location = options[:envelope_location] || :metadata
  if [:metadata, :instruction_file].include?(location)
    location
  else
    msg = ':envelope_location must be :metadata or :instruction_file '\
          "got #{location.inspect}"
    raise ArgumentError, msg
  end
end
extract_security_profile(options) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 533
def extract_security_profile(options)
  validate_security_profile(options[:security_profile])
end
extract_suffix(options) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 515
def extract_suffix(options)
  suffix = options[:instruction_file_suffix] || '.instruction'
  if suffix.is_a? String
    suffix
  else
    msg = ':instruction_file_suffix must be a String'
    raise ArgumentError, msg
  end
end
kms_any_cmk_mode(params) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 525
def kms_any_cmk_mode(params)
  if !params[:kms_allow_decrypt_with_any_cmk].nil?
    params.delete(:kms_allow_decrypt_with_any_cmk)
  else
    @kms_allow_decrypt_with_any_cmk
  end
end
kms_client(options) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 456
def kms_client(options)
  options[:kms_client] || begin
    KMS::Client.new(
      region: @client.config.region,
      credentials: @client.config.credentials,
      )
  end
end
security_profile_from_params(params) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 537
def security_profile_from_params(params)
  security_profile =
    if !params[:security_profile].nil?
      params.delete(:security_profile)
    else
      @security_profile
    end
  validate_security_profile(security_profile)
end
validate_params(options) click to toggle source

Validate required parameters exist and don't conflict. The cek_alg and wrap_alg are passed on to the CipherProviders and further validated there

# File lib/aws-sdk-s3/encryptionV2/client.rb, line 425
def validate_params(options)
  unless (missing_params = REQUIRED_PARAMS - options.keys).empty?
    raise ArgumentError, "Missing required parameter(s): "\
      "#{missing_params.map{ |s| ":#{s}" }.join(', ')}"
  end

  wrap_alg = options[:key_wrap_schema]

  # validate that the wrap alg matches the type of key given
  case wrap_alg
  when :kms_context
    unless options[:kms_key_id]
      raise ArgumentError, 'You must provide :kms_key_id to use :kms_context'
    end
  end
end
validate_security_profile(security_profile) click to toggle source
# File lib/aws-sdk-s3/encryptionV2/client.rb, line 547
def validate_security_profile(security_profile)
  unless SUPPORTED_SECURITY_PROFILES.include? security_profile
    raise ArgumentError, "Unsupported security profile: :#{security_profile}. " \
    "Please provide one of: #{SUPPORTED_SECURITY_PROFILES.map { |s| ":#{s}" }.join(', ')}"
  end
  if security_profile == :v2_and_legacy && !@warned_about_legacy
    @warned_about_legacy = true
    warn(
      'The S3 Encryption Client is configured to read encrypted objects ' \
      "with legacy encryption modes. If you don't have objects " \
      'encrypted with these legacy modes, you should disable support ' \
      'for them to enhance security.'
    )
  end
  security_profile
end