aws-sdk-s3 1.10.0 → 1.208.0

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