aws-sdk-s3 1.36.0 → 1.95.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +768 -0
  3. data/LICENSE.txt +202 -0
  4. data/VERSION +1 -0
  5. data/lib/aws-sdk-s3/arn/access_point_arn.rb +69 -0
  6. data/lib/aws-sdk-s3/arn/object_lambda_arn.rb +69 -0
  7. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +73 -0
  8. data/lib/aws-sdk-s3/bucket.rb +277 -76
  9. data/lib/aws-sdk-s3/bucket_acl.rb +40 -15
  10. data/lib/aws-sdk-s3/bucket_cors.rb +50 -14
  11. data/lib/aws-sdk-s3/bucket_lifecycle.rb +33 -14
  12. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +32 -14
  13. data/lib/aws-sdk-s3/bucket_logging.rb +35 -15
  14. data/lib/aws-sdk-s3/bucket_notification.rb +32 -18
  15. data/lib/aws-sdk-s3/bucket_policy.rb +34 -13
  16. data/lib/aws-sdk-s3/bucket_region_cache.rb +2 -0
  17. data/lib/aws-sdk-s3/bucket_request_payment.rb +34 -12
  18. data/lib/aws-sdk-s3/bucket_tagging.rb +42 -14
  19. data/lib/aws-sdk-s3/bucket_versioning.rb +67 -12
  20. data/lib/aws-sdk-s3/bucket_website.rb +49 -17
  21. data/lib/aws-sdk-s3/client.rb +7494 -618
  22. data/lib/aws-sdk-s3/client_api.rb +417 -2
  23. data/lib/aws-sdk-s3/customizations/bucket.rb +59 -16
  24. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
  25. data/lib/aws-sdk-s3/customizations/object.rb +125 -60
  26. data/lib/aws-sdk-s3/customizations/object_summary.rb +5 -0
  27. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
  28. data/lib/aws-sdk-s3/customizations.rb +4 -1
  29. data/lib/aws-sdk-s3/encryption/client.rb +22 -5
  30. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +72 -26
  31. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +43 -5
  32. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
  33. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +13 -2
  34. data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
  35. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +2 -0
  36. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +11 -3
  37. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
  38. data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
  39. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +34 -3
  40. data/lib/aws-sdk-s3/encryption/materials.rb +8 -6
  41. data/lib/aws-sdk-s3/encryption/utils.rb +25 -0
  42. data/lib/aws-sdk-s3/encryption.rb +4 -0
  43. data/lib/aws-sdk-s3/encryptionV2/client.rb +566 -0
  44. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +226 -0
  45. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +170 -0
  46. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +40 -0
  47. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +69 -0
  48. data/lib/aws-sdk-s3/encryptionV2/errors.rb +37 -0
  49. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +58 -0
  50. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +37 -0
  51. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +73 -0
  52. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +31 -0
  53. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +169 -0
  54. data/lib/aws-sdk-s3/encryptionV2/materials.rb +60 -0
  55. data/lib/aws-sdk-s3/encryptionV2/utils.rb +103 -0
  56. data/lib/aws-sdk-s3/encryption_v2.rb +23 -0
  57. data/lib/aws-sdk-s3/errors.rb +123 -1
  58. data/lib/aws-sdk-s3/event_streams.rb +15 -8
  59. data/lib/aws-sdk-s3/file_downloader.rb +10 -8
  60. data/lib/aws-sdk-s3/file_part.rb +11 -6
  61. data/lib/aws-sdk-s3/file_uploader.rb +28 -14
  62. data/lib/aws-sdk-s3/legacy_signer.rb +17 -25
  63. data/lib/aws-sdk-s3/multipart_file_uploader.rb +53 -13
  64. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +20 -7
  65. data/lib/aws-sdk-s3/multipart_upload.rb +64 -29
  66. data/lib/aws-sdk-s3/multipart_upload_error.rb +2 -0
  67. data/lib/aws-sdk-s3/multipart_upload_part.rb +115 -42
  68. data/lib/aws-sdk-s3/object.rb +656 -151
  69. data/lib/aws-sdk-s3/object_acl.rb +64 -21
  70. data/lib/aws-sdk-s3/object_copier.rb +2 -0
  71. data/lib/aws-sdk-s3/object_multipart_copier.rb +2 -0
  72. data/lib/aws-sdk-s3/object_summary.rb +474 -138
  73. data/lib/aws-sdk-s3/object_version.rb +122 -58
  74. data/lib/aws-sdk-s3/plugins/accelerate.rb +32 -38
  75. data/lib/aws-sdk-s3/plugins/arn.rb +228 -0
  76. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +7 -7
  77. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +25 -3
  78. data/lib/aws-sdk-s3/plugins/dualstack.rb +15 -4
  79. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +4 -4
  80. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +2 -0
  81. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +11 -3
  82. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +67 -0
  83. data/lib/aws-sdk-s3/plugins/location_constraint.rb +2 -0
  84. data/lib/aws-sdk-s3/plugins/md5s.rb +30 -28
  85. data/lib/aws-sdk-s3/plugins/object_lambda_endpoint.rb +25 -0
  86. data/lib/aws-sdk-s3/plugins/redirects.rb +2 -0
  87. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
  88. data/lib/aws-sdk-s3/plugins/s3_signer.rb +64 -35
  89. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +3 -1
  90. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +118 -0
  91. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -0
  92. data/lib/aws-sdk-s3/presigned_post.rb +72 -32
  93. data/lib/aws-sdk-s3/presigner.rb +162 -66
  94. data/lib/aws-sdk-s3/resource.rb +23 -5
  95. data/lib/aws-sdk-s3/types.rb +6441 -952
  96. data/lib/aws-sdk-s3/waiters.rb +67 -1
  97. data/lib/aws-sdk-s3.rb +12 -6
  98. metadata +35 -12
@@ -0,0 +1,566 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Aws
6
+ module S3
7
+
8
+ REQUIRED_PARAMS = [:key_wrap_schema, :content_encryption_schema, :security_profile]
9
+ SUPPORTED_SECURITY_PROFILES = [:v2, :v2_and_legacy]
10
+
11
+ # Provides an encryption client that encrypts and decrypts data client-side,
12
+ # storing the encrypted data in Amazon S3. The `EncryptionV2::Client` (V2 Client)
13
+ # provides improved security over the `Encryption::Client` (V1 Client)
14
+ # by using more modern and secure algorithms. You can use the V2 Client
15
+ # to continue decrypting objects encrypted using deprecated algorithms
16
+ # by setting security_profile: :v2_and_legacy. The latest V1 Client also
17
+ # supports reading and decrypting objects encrypted by the V2 Client.
18
+ #
19
+ # This client uses a process called "envelope encryption". Your private
20
+ # encryption keys and your data's plain-text are **never** sent to
21
+ # Amazon S3. **If you lose you encryption keys, you will not be able to
22
+ # decrypt your data.**
23
+ #
24
+ # ## Envelope Encryption Overview
25
+ #
26
+ # The goal of envelope encryption is to combine the performance of
27
+ # fast symmetric encryption while maintaining the secure key management
28
+ # that asymmetric keys provide.
29
+ #
30
+ # A one-time-use symmetric key (envelope key) is generated client-side.
31
+ # This is used to encrypt the data client-side. This key is then
32
+ # encrypted by your master key and stored alongside your data in Amazon
33
+ # S3.
34
+ #
35
+ # When accessing your encrypted data with the encryption client,
36
+ # the encrypted envelope key is retrieved and decrypted client-side
37
+ # with your master key. The envelope key is then used to decrypt the
38
+ # data client-side.
39
+ #
40
+ # One of the benefits of envelope encryption is that if your master key
41
+ # is compromised, you have the option of just re-encrypting the stored
42
+ # envelope symmetric keys, instead of re-encrypting all of the
43
+ # data in your account.
44
+ #
45
+ # ## Basic Usage
46
+ #
47
+ # The encryption client requires an {Aws::S3::Client}. If you do not
48
+ # provide a `:client`, then a client will be constructed for you.
49
+ #
50
+ # require 'openssl'
51
+ # key = OpenSSL::PKey::RSA.new(1024)
52
+ #
53
+ # # encryption client
54
+ # s3 = Aws::S3::EncryptionV2::Client.new(
55
+ # encryption_key: key,
56
+ # key_wrap_schema: :rsa_oaep_sha1, # the key_wrap_schema must be rsa_oaep_sha1 for asymmetric keys
57
+ # content_encryption_schema: :aes_gcm_no_padding,
58
+ # security_profile: :v2 # use :v2_and_legacy to allow reading/decrypting objects encrypted by the V1 encryption client
59
+ # )
60
+ #
61
+ # # round-trip an object, encrypted/decrypted locally
62
+ # s3.put_object(bucket:'aws-sdk', key:'secret', body:'handshake')
63
+ # s3.get_object(bucket:'aws-sdk', key:'secret').body.read
64
+ # #=> 'handshake'
65
+ #
66
+ # # reading encrypted object without the encryption client
67
+ # # results in the getting the cipher text
68
+ # Aws::S3::Client.new.get_object(bucket:'aws-sdk', key:'secret').body.read
69
+ # #=> "... cipher text ..."
70
+ #
71
+ # ## Required Configuration
72
+ #
73
+ # You must configure all of the following:
74
+ #
75
+ # * a key or key provider - See the Keys section below. The key provided determines
76
+ # the key wrapping schema(s) supported for both encryption and decryption.
77
+ # * `key_wrap_schema` - The key wrapping schema. It must match the type of key configured.
78
+ # * `content_encryption_schema` - The only supported value currently is `:aes_gcm_no_padding`.
79
+ # More options will be added in future releases.
80
+ # * `security_profile` - Determines the support for reading objects written
81
+ # using older key wrap or content encryption schemas. If you need to read
82
+ # legacy objects encrypted by an existing V1 Client, then set this to `:v2_and_legacy`.
83
+ # Otherwise, set it to `:v2`
84
+ #
85
+ # ## Keys
86
+ #
87
+ # For client-side encryption to work, you must provide one of the following:
88
+ #
89
+ # * An encryption key
90
+ # * A {KeyProvider}
91
+ # * A KMS encryption key id
92
+ #
93
+ # Additionally, the key wrapping schema must agree with the type of the key:
94
+ # * :aes_gcm: An AES encryption key or a key provider.
95
+ # * :rsa_oaep_sha1: An RSA encryption key or key provider.
96
+ # * :kms_context: A KMS encryption key id
97
+ #
98
+ # ### An Encryption Key
99
+ #
100
+ # You can pass a single encryption key. This is used as a master key
101
+ # encrypting and decrypting all object keys.
102
+ #
103
+ # key = OpenSSL::Cipher.new("AES-256-ECB").random_key # symmetric key - used with `key_wrap_schema: :aes_gcm`
104
+ # key = OpenSSL::PKey::RSA.new(1024) # asymmetric key pair - used with `key_wrap_schema: :rsa_oaep_sha1`
105
+ #
106
+ # s3 = Aws::S3::EncryptionV2::Client.new(
107
+ # encryption_key: key,
108
+ # key_wrap_schema: :aes_gcm, # or :rsa_oaep_sha1 if using RSA
109
+ # content_encryption_schema: :aes_gcm_no_padding,
110
+ # security_profile: :v2
111
+ # )
112
+ #
113
+ # ### Key Provider
114
+ #
115
+ # Alternatively, you can use a {KeyProvider}. A key provider makes
116
+ # it easy to work with multiple keys and simplifies key rotation.
117
+ #
118
+ # ### KMS Encryption Key Id
119
+ #
120
+ # If you pass the id of an AWS Key Management Service (KMS) key and
121
+ # use :kms_content for the key_wrap_schema, then KMS will be used to
122
+ # generate, encrypt and decrypt object keys.
123
+ #
124
+ # # keep track of the kms key id
125
+ # kms = Aws::KMS::Client.new
126
+ # key_id = kms.create_key.key_metadata.key_id
127
+ #
128
+ # Aws::S3::EncryptionV2::Client.new(
129
+ # kms_key_id: key_id,
130
+ # kms_client: kms,
131
+ # key_wrap_schema: :kms_context,
132
+ # content_encryption_schema: :aes_gcm_no_padding,
133
+ # security_profile: :v2
134
+ # )
135
+ #
136
+ # ## Custom Key Providers
137
+ #
138
+ # A {KeyProvider} is any object that responds to:
139
+ #
140
+ # * `#encryption_materials`
141
+ # * `#key_for(materials_description)`
142
+ #
143
+ # Here is a trivial implementation of an in-memory key provider.
144
+ # This is provided as a demonstration of the key provider interface,
145
+ # and should not be used in production:
146
+ #
147
+ # class KeyProvider
148
+ #
149
+ # def initialize(default_key_name, keys)
150
+ # @keys = keys
151
+ # @encryption_materials = Aws::S3::EncryptionV2::Materials.new(
152
+ # key: @keys[default_key_name],
153
+ # description: JSON.dump(key: default_key_name),
154
+ # )
155
+ # end
156
+ #
157
+ # attr_reader :encryption_materials
158
+ #
159
+ # def key_for(matdesc)
160
+ # key_name = JSON.load(matdesc)['key']
161
+ # if key = @keys[key_name]
162
+ # key
163
+ # else
164
+ # raise "encryption key not found for: #{matdesc.inspect}"
165
+ # end
166
+ # end
167
+ # end
168
+ #
169
+ # Given the above key provider, you can create an encryption client that
170
+ # chooses the key to use based on the materials description stored with
171
+ # the encrypted object. This makes it possible to use multiple keys
172
+ # and simplifies key rotation.
173
+ #
174
+ # # uses "new-key" for encrypting objects, uses either for decrypting
175
+ # keys = KeyProvider.new('new-key', {
176
+ # "old-key" => Base64.decode64("kM5UVbhE/4rtMZJfsadYEdm2vaKFsmV2f5+URSeUCV4="),
177
+ # "new-key" => Base64.decode64("w1WLio3agRWRTSJK/Ouh8NHoqRQ6fn5WbSXDTHjXMSo="),
178
+ # }),
179
+ #
180
+ # # chooses the key based on the materials description stored
181
+ # # with the encrypted object
182
+ # s3 = Aws::S3::EncryptionV2::Client.new(
183
+ # key_provider: keys,
184
+ # key_wrap_schema: ...,
185
+ # content_encryption_schema: :aes_gcm_no_padding,
186
+ # security_profile: :v2
187
+ # )
188
+ #
189
+ # ## Materials Description
190
+ #
191
+ # A materials description is JSON document string that is stored
192
+ # in the metadata (or instruction file) of an encrypted object.
193
+ # The {DefaultKeyProvider} uses the empty JSON document `"{}"`.
194
+ #
195
+ # When building a key provider, you are free to store whatever
196
+ # information you need to identify the master key that was used
197
+ # to encrypt the object.
198
+ #
199
+ # ## Envelope Location
200
+ #
201
+ # By default, the encryption client store the encryption envelope
202
+ # with the object, as metadata. You can choose to have the envelope
203
+ # stored in a separate "instruction file". An instruction file
204
+ # is an object, with the key of the encrypted object, suffixed with
205
+ # `".instruction"`.
206
+ #
207
+ # Specify the `:envelope_location` option as `:instruction_file` to
208
+ # use an instruction file for storing the envelope.
209
+ #
210
+ # # default behavior
211
+ # s3 = Aws::S3::EncryptionV2::Client.new(
212
+ # key_provider: ...,
213
+ # envelope_location: :metadata,
214
+ # )
215
+ #
216
+ # # store envelope in a separate object
217
+ # s3 = Aws::S3::EncryptionV2::Client.new(
218
+ # key_provider: ...,
219
+ # envelope_location: :instruction_file,
220
+ # instruction_file_suffix: '.instruction' # default
221
+ # key_wrap_schema: ...,
222
+ # content_encryption_schema: :aes_gcm_no_padding,
223
+ # security_profile: :v2
224
+ # )
225
+ #
226
+ # When using an instruction file, multiple requests are made when
227
+ # putting and getting the object. **This may cause issues if you are
228
+ # issuing concurrent PUT and GET requests to an encrypted object.**
229
+ #
230
+ module EncryptionV2
231
+ class Client
232
+
233
+ extend Deprecations
234
+ extend Forwardable
235
+ def_delegators :@client, :config, :delete_object, :head_object, :build_request
236
+
237
+ # Creates a new encryption client. You must configure all of the following:
238
+ #
239
+ # * a key or key provider - The key provided also determines the key wrapping
240
+ # schema(s) supported for both encryption and decryption.
241
+ # * `key_wrap_schema` - The key wrapping schema. It must match the type of key configured.
242
+ # * `content_encryption_schema` - The only supported value currently is `:aes_gcm_no_padding`
243
+ # More options will be added in future releases.
244
+ # * `security_profile` - Determines the support for reading objects written
245
+ # using older key wrap or content encryption schemas. If you need to read
246
+ # legacy objects encrypted by an existing V1 Client, then set this to `:v2_and_legacy`.
247
+ # Otherwise, set it to `:v2`
248
+ #
249
+ # To configure the key you must provide one of the following set of options:
250
+ #
251
+ # * `:encryption_key`
252
+ # * `:kms_key_id`
253
+ # * `:key_provider`
254
+ #
255
+ # You may also pass any other options accepted by `Client#initialize`.
256
+ #
257
+ # @option options [S3::Client] :client A basic S3 client that is used
258
+ # to make api calls. If a `:client` is not provided, a new {S3::Client}
259
+ # will be constructed.
260
+ #
261
+ # @option options [OpenSSL::PKey::RSA, String] :encryption_key The master
262
+ # key to use for encrypting/decrypting all objects.
263
+ #
264
+ # @option options [String] :kms_key_id When you provide a `:kms_key_id`,
265
+ # then AWS Key Management Service (KMS) will be used to manage the
266
+ # object encryption keys. By default a {KMS::Client} will be
267
+ # constructed for KMS API calls. Alternatively, you can provide
268
+ # your own via `:kms_client`. To only support decryption/reads, you may
269
+ # provide `:allow_decrypt_with_any_cmk` which will use
270
+ # the implicit CMK associated with the data during reads but will
271
+ # not allow you to encrypt/write objects with this client.
272
+ #
273
+ # @option options [#key_for] :key_provider Any object that responds
274
+ # to `#key_for`. This method should accept a materials description
275
+ # JSON document string and return return an encryption key.
276
+ #
277
+ # @option options [required, Symbol] :key_wrap_schema The Key wrapping
278
+ # schema to be used. It must match the type of key configured.
279
+ # Must be one of the following:
280
+ #
281
+ # * :kms_context (Must provide kms_key_id)
282
+ # * :aes_gcm (Must provide an AES (string) key)
283
+ # * :rsa_oaep_sha1 (Must provide an RSA key)
284
+ #
285
+ # @option options [required, Symbol] :content_encryption_schema
286
+ # Must be one of the following:
287
+ #
288
+ # * :aes_gcm_no_padding
289
+ #
290
+ # @option options [Required, Symbol] :security_profile
291
+ # Determines the support for reading objects written using older
292
+ # key wrap or content encryption schemas.
293
+ # Must be one of the following:
294
+ #
295
+ # * :v2 - Reads of legacy (v1) objects are NOT allowed
296
+ # * :v2_and_legacy - Enables reading of legacy (V1) schemas.
297
+ #
298
+ # @option options [Symbol] :envelope_location (:metadata) Where to
299
+ # store the envelope encryption keys. By default, the envelope is
300
+ # stored with the encrypted object. If you pass `:instruction_file`,
301
+ # then the envelope is stored in a separate object in Amazon S3.
302
+ #
303
+ # @option options [String] :instruction_file_suffix ('.instruction')
304
+ # When `:envelope_location` is `:instruction_file` then the
305
+ # instruction file uses the object key with this suffix appended.
306
+ #
307
+ # @option options [KMS::Client] :kms_client A default {KMS::Client}
308
+ # is constructed when using KMS to manage encryption keys.
309
+ #
310
+ def initialize(options = {})
311
+ validate_params(options)
312
+ @client = extract_client(options)
313
+ @cipher_provider = cipher_provider(options)
314
+ @envelope_location = extract_location(options)
315
+ @instruction_file_suffix = extract_suffix(options)
316
+ @kms_allow_decrypt_with_any_cmk =
317
+ options[:kms_key_id] == :kms_allow_decrypt_with_any_cmk
318
+ @security_profile = extract_security_profile(options)
319
+ end
320
+
321
+ # @return [S3::Client]
322
+ attr_reader :client
323
+
324
+ # @return [KeyProvider, nil] Returns `nil` if you are using
325
+ # AWS Key Management Service (KMS).
326
+ attr_reader :key_provider
327
+
328
+ # @return [Symbol] Determines the support for reading objects written
329
+ # using older key wrap or content encryption schemas.
330
+ attr_reader :security_profile
331
+
332
+ # @return [Boolean] If true the provided KMS key_id will not be used
333
+ # during decrypt, allowing decryption with the key_id from the object.
334
+ attr_reader :kms_allow_decrypt_with_any_cmk
335
+
336
+ # @return [Symbol<:metadata, :instruction_file>]
337
+ attr_reader :envelope_location
338
+
339
+ # @return [String] When {#envelope_location} is `:instruction_file`,
340
+ # the envelope is stored in the object with the object key suffixed
341
+ # by this string.
342
+ attr_reader :instruction_file_suffix
343
+
344
+ # Uploads an object to Amazon S3, encrypting data client-side.
345
+ # See {S3::Client#put_object} for documentation on accepted
346
+ # request parameters.
347
+ # @option params [Hash] :kms_encryption_context Additional encryption
348
+ # context to use with KMS. Applies only when KMS is used. In order
349
+ # to decrypt the object you will need to provide the identical
350
+ # :kms_encryption_context to `get_object`.
351
+ # @option (see S3::Client#put_object)
352
+ # @return (see S3::Client#put_object)
353
+ # @see S3::Client#put_object
354
+ def put_object(params = {})
355
+ kms_encryption_context = params.delete(:kms_encryption_context)
356
+ req = @client.build_request(:put_object, params)
357
+ req.handlers.add(EncryptHandler, priority: 95)
358
+ req.context[:encryption] = {
359
+ cipher_provider: @cipher_provider,
360
+ envelope_location: @envelope_location,
361
+ instruction_file_suffix: @instruction_file_suffix,
362
+ kms_encryption_context: kms_encryption_context
363
+ }
364
+ req.send_request
365
+ end
366
+
367
+ # Gets an object from Amazon S3, decrypting data locally.
368
+ # See {S3::Client#get_object} for documentation on accepted
369
+ # request parameters.
370
+ # Warning: If you provide a block to get_object or set the request
371
+ # parameter :response_target to a Proc, then read the entire object to the
372
+ # end before you start using the decrypted data. This is to verify that
373
+ # the object has not been modified since it was encrypted.
374
+ #
375
+ # @option options [Symbol] :security_profile
376
+ # Determines the support for reading objects written using older
377
+ # key wrap or content encryption schemas. Overrides the value set
378
+ # on client construction if provided.
379
+ # Must be one of the following:
380
+ #
381
+ # * :v2 - Reads of legacy (v1) objects are NOT allowed
382
+ # * :v2_and_legacy - Enables reading of legacy (V1) schemas.
383
+ # @option params [String] :instruction_file_suffix The suffix
384
+ # used to find the instruction file containing the encryption
385
+ # envelope. You should not set this option when the envelope
386
+ # is stored in the object metadata. Defaults to
387
+ # {#instruction_file_suffix}.
388
+ # @option params [Hash] :kms_encryption_context Additional encryption
389
+ # context to use with KMS. Applies only when KMS is used.
390
+ # @option options [Boolean] :kms_allow_decrypt_with_any_cmk (false)
391
+ # By default the KMS CMK ID (kms_key_id) will be used during decrypt
392
+ # and will fail if there is a mismatch. Setting this to true
393
+ # will use the implicit CMK associated with the data.
394
+ # @option (see S3::Client#get_object)
395
+ # @return (see S3::Client#get_object)
396
+ # @see S3::Client#get_object
397
+ # @note The `:range` request parameter is not supported.
398
+ def get_object(params = {}, &block)
399
+ if params[:range]
400
+ raise NotImplementedError, '#get_object with :range not supported'
401
+ end
402
+ envelope_location, instruction_file_suffix = envelope_options(params)
403
+ kms_encryption_context = params.delete(:kms_encryption_context)
404
+ kms_any_cmk_mode = kms_any_cmk_mode(params)
405
+ security_profile = security_profile_from_params(params)
406
+
407
+ req = @client.build_request(:get_object, params)
408
+ req.handlers.add(DecryptHandler)
409
+ req.context[:encryption] = {
410
+ cipher_provider: @cipher_provider,
411
+ envelope_location: envelope_location,
412
+ instruction_file_suffix: instruction_file_suffix,
413
+ kms_encryption_context: kms_encryption_context,
414
+ kms_allow_decrypt_with_any_cmk: kms_any_cmk_mode,
415
+ security_profile: security_profile
416
+ }
417
+ req.send_request(target: block)
418
+ end
419
+
420
+ private
421
+
422
+ # Validate required parameters exist and don't conflict.
423
+ # The cek_alg and wrap_alg are passed on to the CipherProviders
424
+ # and further validated there
425
+ def validate_params(options)
426
+ unless (missing_params = REQUIRED_PARAMS - options.keys).empty?
427
+ raise ArgumentError, "Missing required parameter(s): "\
428
+ "#{missing_params.map{ |s| ":#{s}" }.join(', ')}"
429
+ end
430
+
431
+ wrap_alg = options[:key_wrap_schema]
432
+
433
+ # validate that the wrap alg matches the type of key given
434
+ case wrap_alg
435
+ when :kms_context
436
+ unless options[:kms_key_id]
437
+ raise ArgumentError, 'You must provide :kms_key_id to use :kms_context'
438
+ end
439
+ end
440
+ end
441
+
442
+ def extract_client(options)
443
+ options[:client] || begin
444
+ options = options.dup
445
+ options.delete(:kms_key_id)
446
+ options.delete(:kms_client)
447
+ options.delete(:key_provider)
448
+ options.delete(:encryption_key)
449
+ options.delete(:envelope_location)
450
+ options.delete(:instruction_file_suffix)
451
+ REQUIRED_PARAMS.each { |p| options.delete(p) }
452
+ S3::Client.new(options)
453
+ end
454
+ end
455
+
456
+ def kms_client(options)
457
+ options[:kms_client] || begin
458
+ KMS::Client.new(
459
+ region: @client.config.region,
460
+ credentials: @client.config.credentials,
461
+ )
462
+ end
463
+ end
464
+
465
+ def cipher_provider(options)
466
+ if options[:kms_key_id]
467
+ KmsCipherProvider.new(
468
+ kms_key_id: options[:kms_key_id],
469
+ kms_client: kms_client(options),
470
+ key_wrap_schema: options[:key_wrap_schema],
471
+ content_encryption_schema: options[:content_encryption_schema]
472
+ )
473
+ else
474
+ @key_provider = extract_key_provider(options)
475
+ DefaultCipherProvider.new(
476
+ key_provider: @key_provider,
477
+ key_wrap_schema: options[:key_wrap_schema],
478
+ content_encryption_schema: options[:content_encryption_schema]
479
+ )
480
+ end
481
+ end
482
+
483
+ def extract_key_provider(options)
484
+ if options[:key_provider]
485
+ options[:key_provider]
486
+ elsif options[:encryption_key]
487
+ DefaultKeyProvider.new(options)
488
+ else
489
+ msg = 'you must pass a :kms_key_id, :key_provider, or :encryption_key'
490
+ raise ArgumentError, msg
491
+ end
492
+ end
493
+
494
+ def envelope_options(params)
495
+ location = params.delete(:envelope_location) || @envelope_location
496
+ suffix = params.delete(:instruction_file_suffix)
497
+ if suffix
498
+ [:instruction_file, suffix]
499
+ else
500
+ [location, @instruction_file_suffix]
501
+ end
502
+ end
503
+
504
+ def extract_location(options)
505
+ location = options[:envelope_location] || :metadata
506
+ if [:metadata, :instruction_file].include?(location)
507
+ location
508
+ else
509
+ msg = ':envelope_location must be :metadata or :instruction_file '\
510
+ "got #{location.inspect}"
511
+ raise ArgumentError, msg
512
+ end
513
+ end
514
+
515
+ def extract_suffix(options)
516
+ suffix = options[:instruction_file_suffix] || '.instruction'
517
+ if suffix.is_a? String
518
+ suffix
519
+ else
520
+ msg = ':instruction_file_suffix must be a String'
521
+ raise ArgumentError, msg
522
+ end
523
+ end
524
+
525
+ def kms_any_cmk_mode(params)
526
+ if !params[:kms_allow_decrypt_with_any_cmk].nil?
527
+ params.delete(:kms_allow_decrypt_with_any_cmk)
528
+ else
529
+ @kms_allow_decrypt_with_any_cmk
530
+ end
531
+ end
532
+
533
+ def extract_security_profile(options)
534
+ validate_security_profile(options[:security_profile])
535
+ end
536
+
537
+ def security_profile_from_params(params)
538
+ security_profile =
539
+ if !params[:security_profile].nil?
540
+ params.delete(:security_profile)
541
+ else
542
+ @security_profile
543
+ end
544
+ validate_security_profile(security_profile)
545
+ end
546
+
547
+ def validate_security_profile(security_profile)
548
+ unless SUPPORTED_SECURITY_PROFILES.include? security_profile
549
+ raise ArgumentError, "Unsupported security profile: :#{security_profile}. " \
550
+ "Please provide one of: #{SUPPORTED_SECURITY_PROFILES.map { |s| ":#{s}" }.join(', ')}"
551
+ end
552
+ if security_profile == :v2_and_legacy && !@warned_about_legacy
553
+ @warned_about_legacy = true
554
+ warn(
555
+ 'The S3 Encryption Client is configured to read encrypted objects ' \
556
+ "with legacy encryption modes. If you don't have objects " \
557
+ 'encrypted with these legacy modes, you should disable support ' \
558
+ 'for them to enhance security.'
559
+ )
560
+ end
561
+ security_profile
562
+ end
563
+ end
564
+ end
565
+ end
566
+ end