aws-sdk-core 3.185.1 → 3.188.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a871c58d68eb4fb29e8cbaa37367987ed2c060127ddddd433235ae50b43030f5
4
- data.tar.gz: f7697299235319ae5cb27f2251d2650960e68358d30ea90199bcc4709ef6bd81
3
+ metadata.gz: 116ce287a47541305621ccf38cc1e53f756812b453ad271432f09b149e0a6a1e
4
+ data.tar.gz: dead4ace5e8003c81b726f8d33e4d9a87ef67d4ee05f9db0a1b597a0e08efeed
5
5
  SHA512:
6
- metadata.gz: 2e2f2575b51ecc6cebcb91657b12e88241cb7b51a635fa48057f7f54b540cee470d0eef5c20dc5da4e0c8f9c4f967133c3a100824c2e274978131ee86ab69c5e
7
- data.tar.gz: 2dd958969ee80dbde1b6fe9c151f5508301593ad87703ebbb0a4b700e57110ad88e3a1103a56bc70cb5cdfe2965eb0fbb27ee35d38adfa45e664a958546ddb7e
6
+ metadata.gz: 5c8e05a07f49a55341bd54cfc39da5383de63172059a51167f26d6410d94f2a2dc6b5afa184efcbd565606e82a4706804d80c7da19ee3a6e32023e743cd24651
7
+ data.tar.gz: 8e2b3599e93a1fbaa7e1db5509b76a522a0eed215b6823d92cd90575829ace8f0d647e7c936d37ce067a9a25c105761d866fb34239e426240193802aa7d28658
data/CHANGELOG.md CHANGED
@@ -1,6 +1,35 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 3.188.0 (2023-11-22)
5
+ ------------------
6
+
7
+ * Feature - AWS SDK for Ruby no longer supports Ruby runtime versions 2.3 and 2.4.
8
+
9
+ * Feature - Support `AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE` in `ECSCredentials` and also allow for ECS and EKS link-local http addresses.
10
+
11
+ 3.187.1 (2023-11-20)
12
+ ------------------
13
+
14
+ * Issue - For `awsQueryCompatible` services, default an empty list or map for shapes that were previously flattened in the query protocol.
15
+
16
+ 3.187.0 (2023-11-17)
17
+ ------------------
18
+
19
+ * Feature - Updated Aws::STS::Client with the latest API changes.
20
+
21
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
22
+
23
+ 3.186.0 (2023-11-02)
24
+ ------------------
25
+
26
+ * Feature - Support disabling IMDSv1 in `InstanceProfileCredentials` using `ENV['AWS_EC2_METADATA_V1_DISABLED']`, `ec2_metadata_v1_disabled` shared config, or the `disable_imds_v1` credentials option.
27
+
28
+ 3.185.2 (2023-10-31)
29
+ ------------------
30
+
31
+ * Issue - Fix query string support to lists of booleans, floats, integers and timestamps per rest-json protocol.
32
+
4
33
  3.185.1 (2023-10-05)
5
34
  ------------------
6
35
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.185.1
1
+ 3.188.0
@@ -6,7 +6,7 @@ require 'resolv'
6
6
 
7
7
  module Aws
8
8
  # An auto-refreshing credential provider that loads credentials from
9
- # instances running in ECS.
9
+ # instances running in containers.
10
10
  #
11
11
  # ecs_credentials = Aws::ECSCredentials.new(retries: 3)
12
12
  # ec2 = Aws::EC2::Client.new(credentials: ecs_credentials)
@@ -17,6 +17,12 @@ module Aws
17
17
  # @api private
18
18
  class Non200Response < RuntimeError; end
19
19
 
20
+ # Raised when the token file cannot be read.
21
+ class TokenFileReadError < RuntimeError; end
22
+
23
+ # Raised when the token file is invalid.
24
+ class InvalidTokenError < RuntimeError; end
25
+
20
26
  # These are the errors we trap when attempting to talk to the
21
27
  # instance metadata service. Any of these imply the service
22
28
  # is not present, no responding or some other non-recoverable
@@ -41,7 +47,7 @@ module Aws
41
47
  # is set and `credential_path` is not set.
42
48
  # @option options [String] :credential_path By default, the value of the
43
49
  # AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variable.
44
- # @option options [String] :endpoint The ECS credential endpoint.
50
+ # @option options [String] :endpoint The container credential endpoint.
45
51
  # By default, this is the value of the AWS_CONTAINER_CREDENTIALS_FULL_URI
46
52
  # environment variable. This value is ignored if `credential_path` or
47
53
  # ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] is set.
@@ -64,7 +70,6 @@ module Aws
64
70
  endpoint = options[:endpoint] ||
65
71
  ENV['AWS_CONTAINER_CREDENTIALS_FULL_URI']
66
72
  initialize_uri(options, credential_path, endpoint)
67
- @authorization_token = ENV['AWS_CONTAINER_AUTHORIZATION_TOKEN']
68
73
 
69
74
  @retries = options[:retries] || 5
70
75
  @http_open_timeout = options[:http_open_timeout] || 5
@@ -103,11 +108,18 @@ module Aws
103
108
 
104
109
  def initialize_full_uri(endpoint)
105
110
  uri = URI.parse(endpoint)
111
+ validate_full_uri_scheme!(uri)
106
112
  validate_full_uri!(uri)
107
- @host = uri.host
113
+ @host = uri.hostname
108
114
  @port = uri.port
109
115
  @scheme = uri.scheme
110
- @credential_path = uri.path
116
+ @credential_path = uri.request_uri
117
+ end
118
+
119
+ def validate_full_uri_scheme!(full_uri)
120
+ return if full_uri.is_a?(URI::HTTP) || full_uri.is_a?(URI::HTTPS)
121
+
122
+ raise ArgumentError, "'#{full_uri}' must be a valid HTTP or HTTPS URI"
111
123
  end
112
124
 
113
125
  # Validate that the full URI is using a loopback address if scheme is http.
@@ -115,19 +127,24 @@ module Aws
115
127
  return unless full_uri.scheme == 'http'
116
128
 
117
129
  begin
118
- return if ip_loopback?(IPAddr.new(full_uri.host))
130
+ return if valid_ip_address?(IPAddr.new(full_uri.host))
119
131
  rescue IPAddr::InvalidAddressError
120
132
  addresses = Resolv.getaddresses(full_uri.host)
121
- return if addresses.all? { |addr| ip_loopback?(IPAddr.new(addr)) }
133
+ return if addresses.all? { |addr| valid_ip_address?(IPAddr.new(addr)) }
122
134
  end
123
135
 
124
136
  raise ArgumentError,
125
- 'AWS_CONTAINER_CREDENTIALS_FULL_URI must use a loopback '\
126
- 'address when using the http scheme.'
137
+ 'AWS_CONTAINER_CREDENTIALS_FULL_URI must use a local loopback '\
138
+ 'or an ECS or EKS link-local address when using the http scheme.'
139
+ end
140
+
141
+ def valid_ip_address?(ip_address)
142
+ ip_loopback?(ip_address) || ecs_or_eks_ip?(ip_address)
127
143
  end
128
144
 
129
145
  # loopback? method is available in Ruby 2.5+
130
146
  # Replicate the logic here.
147
+ # loopback (IPv4 127.0.0.0/8, IPv6 ::1/128)
131
148
  def ip_loopback?(ip_address)
132
149
  case ip_address.family
133
150
  when Socket::AF_INET
@@ -139,6 +156,20 @@ module Aws
139
156
  end
140
157
  end
141
158
 
159
+ # Verify that the IP address is a link-local address from ECS or EKS.
160
+ # ECS container host (IPv4 `169.254.170.2`)
161
+ # EKS container host (IPv4 `169.254.170.23`, IPv6 `fd00:ec2::23`)
162
+ def ecs_or_eks_ip?(ip_address)
163
+ case ip_address.family
164
+ when Socket::AF_INET
165
+ [0xa9feaa02, 0xa9feaa17].include?(ip_address)
166
+ when Socket::AF_INET6
167
+ ip_address == 0xfd00_0ec2_0000_0000_0000_0000_0000_0023
168
+ else
169
+ false
170
+ end
171
+ end
172
+
142
173
  def backoff(backoff)
143
174
  case backoff
144
175
  when Proc then backoff
@@ -174,10 +205,36 @@ module Aws
174
205
  http_get(conn, @credential_path)
175
206
  end
176
207
  end
208
+ rescue TokenFileReadError, InvalidTokenError
209
+ raise
177
210
  rescue StandardError
178
211
  '{}'
179
212
  end
180
213
 
214
+ def fetch_authorization_token
215
+ if (path = ENV['AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE'])
216
+ fetch_authorization_token_file(path)
217
+ elsif (token = ENV['AWS_CONTAINER_AUTHORIZATION_TOKEN'])
218
+ token
219
+ end
220
+ end
221
+
222
+ def fetch_authorization_token_file(path)
223
+ File.read(path).strip
224
+ rescue Errno::ENOENT
225
+ raise TokenFileReadError,
226
+ 'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE is set '\
227
+ "but the file doesn't exist: #{path}"
228
+ end
229
+
230
+ def validate_authorization_token!(token)
231
+ return unless token.include?("\r\n")
232
+
233
+ raise InvalidTokenError,
234
+ 'Invalid Authorization token: token contains '\
235
+ 'a newline and carriage return character.'
236
+ end
237
+
181
238
  def open_connection
182
239
  http = Net::HTTP.new(@host, @port, nil)
183
240
  http.open_timeout = @http_open_timeout
@@ -190,18 +247,27 @@ module Aws
190
247
 
191
248
  def http_get(connection, path)
192
249
  request = Net::HTTP::Get.new(path)
193
- request['Authorization'] = @authorization_token if @authorization_token
250
+ set_authorization_token(request)
194
251
  response = connection.request(request)
195
252
  raise Non200Response unless response.code.to_i == 200
196
253
 
197
254
  response.body
198
255
  end
199
256
 
257
+ def set_authorization_token(request)
258
+ if (authorization_token = fetch_authorization_token)
259
+ validate_authorization_token!(authorization_token)
260
+ request['Authorization'] = authorization_token
261
+ end
262
+ end
263
+
200
264
  def retry_errors(error_classes, options = {})
201
265
  max_retries = options[:max_retries]
202
266
  retries = 0
203
267
  begin
204
268
  yield
269
+ rescue TokenFileReadError, InvalidTokenError
270
+ raise
205
271
  rescue *error_classes => _e
206
272
  raise unless retries < max_retries
207
273
 
@@ -53,6 +53,8 @@ module Aws
53
53
  # @option options [String] :endpoint_mode ('IPv4') The endpoint mode for
54
54
  # the instance metadata service. This is either 'IPv4' ('169.254.169.254')
55
55
  # or 'IPv6' ('[fd00:ec2::254]').
56
+ # @option options [Boolean] :disable_imds_v1 (false) Disable the use of the
57
+ # legacy EC2 Metadata Service v1.
56
58
  # @option options [String] :ip_address ('169.254.169.254') Deprecated. Use
57
59
  # :endpoint instead. The IP address for the endpoint.
58
60
  # @option options [Integer] :port (80)
@@ -77,6 +79,9 @@ module Aws
77
79
  endpoint_mode = resolve_endpoint_mode(options)
78
80
  @endpoint = resolve_endpoint(options, endpoint_mode)
79
81
  @port = options[:port] || 80
82
+ @disable_imds_v1 = resolve_disable_v1(options)
83
+ # Flag for if v2 flow fails, skip future attempts
84
+ @imds_v1_fallback = false
80
85
  @http_open_timeout = options[:http_open_timeout] || 1
81
86
  @http_read_timeout = options[:http_read_timeout] || 1
82
87
  @http_debug_output = options[:http_debug_output]
@@ -123,6 +128,16 @@ module Aws
123
128
  end
124
129
  end
125
130
 
131
+ def resolve_disable_v1(options)
132
+ value = options[:disable_imds_v1]
133
+ value ||= ENV['AWS_EC2_METADATA_V1_DISABLED']
134
+ value ||= Aws.shared_config.ec2_metadata_v1_disabled(
135
+ profile: options[:profile]
136
+ )
137
+ value = value.to_s.downcase if value
138
+ Aws::Util.str_2_bool(value) || false
139
+ end
140
+
126
141
  def backoff(backoff)
127
142
  case backoff
128
143
  when Proc then backoff
@@ -141,7 +156,7 @@ module Aws
141
156
  # service is responding but is returning invalid JSON documents
142
157
  # in response to the GET profile credentials call.
143
158
  begin
144
- retry_errors([Aws::Json::ParseError, StandardError], max_retries: 3) do
159
+ retry_errors([Aws::Json::ParseError], max_retries: 3) do
145
160
  c = Aws::Json.load(get_credentials.to_s)
146
161
  if empty_credentials?(@credentials)
147
162
  @credentials = Credentials.new(
@@ -173,7 +188,6 @@ module Aws
173
188
  end
174
189
  end
175
190
  end
176
-
177
191
  end
178
192
  rescue Aws::Json::ParseError
179
193
  raise Aws::Errors::MetadataParserError
@@ -191,34 +205,14 @@ module Aws
191
205
  open_connection do |conn|
192
206
  # attempt to fetch token to start secure flow first
193
207
  # and rescue to failover
194
- begin
195
- retry_errors(NETWORK_ERRORS, max_retries: @retries) do
196
- unless token_set?
197
- created_time = Time.now
198
- token_value, ttl = http_put(
199
- conn, METADATA_TOKEN_PATH, @token_ttl
200
- )
201
- @token = Token.new(token_value, ttl, created_time) if token_value && ttl
202
- end
203
- end
204
- rescue *NETWORK_ERRORS
205
- # token attempt failed, reset token
206
- # fallback to non-token mode
207
- @token = nil
208
- end
209
-
208
+ fetch_token(conn) unless @imds_v1_fallback
210
209
  token = @token.value if token_set?
211
210
 
212
- begin
213
- metadata = http_get(conn, METADATA_PATH_BASE, token)
214
- profile_name = metadata.lines.first.strip
215
- http_get(conn, METADATA_PATH_BASE + profile_name, token)
216
- rescue TokenExpiredError
217
- # Token has expired, reset it
218
- # The next retry should fetch it
219
- @token = nil
220
- raise Non200Response
221
- end
211
+ # disable insecure flow if we couldn't get token
212
+ # and imds v1 is disabled
213
+ raise TokenRetrivalError if token.nil? && @disable_imds_v1
214
+
215
+ _get_credentials(conn, token)
222
216
  end
223
217
  end
224
218
  rescue
@@ -227,6 +221,36 @@ module Aws
227
221
  end
228
222
  end
229
223
 
224
+ def fetch_token(conn)
225
+ retry_errors(NETWORK_ERRORS, max_retries: @retries) do
226
+ unless token_set?
227
+ created_time = Time.now
228
+ token_value, ttl = http_put(
229
+ conn, METADATA_TOKEN_PATH, @token_ttl
230
+ )
231
+ @token = Token.new(token_value, ttl, created_time) if token_value && ttl
232
+ end
233
+ end
234
+ rescue *NETWORK_ERRORS
235
+ # token attempt failed, reset token
236
+ # fallback to non-token mode
237
+ @token = nil
238
+ @imds_v1_fallback = true
239
+ end
240
+
241
+ # token is optional - if nil, uses v1 (insecure) flow
242
+ def _get_credentials(conn, token)
243
+ metadata = http_get(conn, METADATA_PATH_BASE, token)
244
+ profile_name = metadata.lines.first.strip
245
+ http_get(conn, METADATA_PATH_BASE + profile_name, token)
246
+ rescue TokenExpiredError
247
+ # Token has expired, reset it
248
+ # The next retry should fetch it
249
+ @token = nil
250
+ @imds_v1_fallback = false
251
+ raise Non200Response
252
+ end
253
+
230
254
  def token_set?
231
255
  @token && !@token.expired?
232
256
  end
@@ -276,8 +300,6 @@ module Aws
276
300
  ]
277
301
  when 400
278
302
  raise TokenRetrivalError
279
- when 401
280
- raise TokenExpiredError
281
303
  else
282
304
  raise Non200Response
283
305
  end
@@ -59,7 +59,10 @@ module Aws
59
59
  end
60
60
  resp_struct
61
61
  else
62
- Parser.new(rules).parse(json == '' ? '{}' : json)
62
+ Parser.new(
63
+ rules,
64
+ query_compatible: query_compatible?(context)
65
+ ).parse(json == '' ? '{}' : json)
63
66
  end
64
67
  else
65
68
  EmptyStructure.new
@@ -83,6 +86,10 @@ module Aws
83
86
  context.config.simple_json
84
87
  end
85
88
 
89
+ def query_compatible?(context)
90
+ context.config.api.metadata.key?('awsQueryCompatible')
91
+ end
92
+
86
93
  end
87
94
  end
88
95
  end
@@ -10,8 +10,9 @@ module Aws
10
10
  include Seahorse::Model::Shapes
11
11
 
12
12
  # @param [Seahorse::Model::ShapeRef] rules
13
- def initialize(rules)
13
+ def initialize(rules, query_compatible: false)
14
14
  @rules = rules
15
+ @query_compatible = query_compatible
15
16
  end
16
17
 
17
18
  # @param [String<JSON>] json
@@ -32,6 +33,22 @@ module Aws
32
33
  target[:unknown] = { 'name' => key, 'value' => value }
33
34
  end
34
35
  end
36
+ # In services that were previously Query/XML, members that were
37
+ # "flattened" defaulted to empty lists. In JSON, these values are nil,
38
+ # which is backwards incompatible. To preserve backwards compatibility,
39
+ # we set a default value of [] for these members.
40
+ if @query_compatible
41
+ ref.shape.members.each do |member_name, member_target|
42
+ next unless target[member_name].nil?
43
+
44
+ if flattened_list?(member_target.shape)
45
+ target[member_name] = []
46
+ elsif flattened_map?(member_target.shape)
47
+ target[member_name] = {}
48
+ end
49
+ end
50
+ end
51
+
35
52
  if shape.union
36
53
  # convert to subclass
37
54
  member_subclass = shape.member_subclass(target.member).new
@@ -79,6 +96,14 @@ module Aws
79
96
  value.is_a?(Numeric) ? Time.at(value) : Time.parse(value)
80
97
  end
81
98
 
99
+ def flattened_list?(shape)
100
+ shape.is_a?(ListShape) && shape.flattened
101
+ end
102
+
103
+ def flattened_map?(shape)
104
+ shape.is_a?(MapShape) && shape.flattened
105
+ end
106
+
82
107
  end
83
108
  end
84
109
  end
@@ -4,9 +4,16 @@ module Aws
4
4
  module Rest
5
5
  module Request
6
6
  class QuerystringBuilder
7
-
8
7
  include Seahorse::Model::Shapes
9
8
 
9
+ SUPPORTED_TYPES = [
10
+ BooleanShape,
11
+ FloatShape,
12
+ IntegerShape,
13
+ StringShape,
14
+ TimestampShape
15
+ ].freeze
16
+
10
17
  # Provide shape references and param values:
11
18
  #
12
19
  # [
@@ -33,29 +40,12 @@ module Aws
33
40
  def build_part(shape_ref, param_value)
34
41
  case shape_ref.shape
35
42
  # supported scalar types
36
- when StringShape, BooleanShape, FloatShape, IntegerShape, StringShape
37
- param_name = shape_ref.location_name
38
- "#{param_name}=#{escape(param_value.to_s)}"
39
- when TimestampShape
40
- param_name = shape_ref.location_name
41
- "#{param_name}=#{escape(timestamp(shape_ref, param_value))}"
43
+ when *SUPPORTED_TYPES
44
+ "#{shape_ref.location_name}=#{query_value(shape_ref, param_value)}"
42
45
  when MapShape
43
- if StringShape === shape_ref.shape.value.shape
44
- query_map_of_string(param_value)
45
- elsif ListShape === shape_ref.shape.value.shape
46
- query_map_of_string_list(param_value)
47
- else
48
- msg = "only map of string and string list supported"
49
- raise NotImplementedError, msg
50
- end
46
+ generate_query_map(shape_ref, param_value)
51
47
  when ListShape
52
- if StringShape === shape_ref.shape.member.shape
53
- list_of_strings(shape_ref.location_name, param_value)
54
- else
55
- msg = "Only list of strings supported, got "\
56
- "#{shape_ref.shape.member.shape.class.name}"
57
- raise NotImplementedError, msg
58
- end
48
+ generate_query_list(shape_ref, param_value)
59
49
  else
60
50
  raise NotImplementedError
61
51
  end
@@ -71,6 +61,37 @@ module Aws
71
61
  end
72
62
  end
73
63
 
64
+ def query_value(ref, value)
65
+ case ref.shape
66
+ when TimestampShape
67
+ escape(timestamp(ref, value))
68
+ when *SUPPORTED_TYPES
69
+ escape(value.to_s)
70
+ else
71
+ raise NotImplementedError
72
+ end
73
+ end
74
+
75
+ def generate_query_list(ref, values)
76
+ member_ref = ref.shape.member
77
+ values.map do |value|
78
+ value = query_value(member_ref, value)
79
+ "#{ref.location_name}=#{value}"
80
+ end
81
+ end
82
+
83
+ def generate_query_map(ref, value)
84
+ case ref.shape.value.shape
85
+ when StringShape
86
+ query_map_of_string(value)
87
+ when ListShape
88
+ query_map_of_string_list(value)
89
+ else
90
+ msg = 'Only map of string and string list supported'
91
+ raise NotImplementedError, msg
92
+ end
93
+ end
94
+
74
95
  def query_map_of_string(hash)
75
96
  list = []
76
97
  hash.each_pair do |key, value|
@@ -89,16 +110,9 @@ module Aws
89
110
  list
90
111
  end
91
112
 
92
- def list_of_strings(name, values)
93
- values.map do |value|
94
- "#{name}=#{escape(value)}"
95
- end
96
- end
97
-
98
113
  def escape(string)
99
114
  Seahorse::Util.uri_escape(string)
100
115
  end
101
-
102
116
  end
103
117
  end
104
118
  end
@@ -205,6 +205,7 @@ module Aws
205
205
  :use_fips_endpoint,
206
206
  :ec2_metadata_service_endpoint,
207
207
  :ec2_metadata_service_endpoint_mode,
208
+ :ec2_metadata_v1_disabled,
208
209
  :max_attempts,
209
210
  :retry_mode,
210
211
  :adaptive_retry_wait_to_fill,
@@ -605,7 +605,7 @@ module Aws::SSO
605
605
  params: params,
606
606
  config: config)
607
607
  context[:gem_name] = 'aws-sdk-core'
608
- context[:gem_version] = '3.185.1'
608
+ context[:gem_version] = '3.188.0'
609
609
  Seahorse::Client::Request.new(handlers, context)
610
610
  end
611
611
 
data/lib/aws-sdk-sso.rb CHANGED
@@ -54,6 +54,6 @@ require_relative 'aws-sdk-sso/customizations'
54
54
  # @!group service
55
55
  module Aws::SSO
56
56
 
57
- GEM_VERSION = '3.185.1'
57
+ GEM_VERSION = '3.188.0'
58
58
 
59
59
  end