6
6
7
7
module Aws
8
8
# An auto-refreshing credential provider that loads credentials from
9
- # instances running in containers .
9
+ # instances running in ECS .
10
10
#
11
11
# ecs_credentials = Aws::ECSCredentials.new(retries: 3)
12
12
# ec2 = Aws::EC2::Client.new(credentials: ecs_credentials)
@@ -17,12 +17,6 @@ class ECSCredentials
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
-
26
20
# These are the errors we trap when attempting to talk to the
27
21
# instance metadata service. Any of these imply the service
28
22
# is not present, no responding or some other non-recoverable
@@ -47,7 +41,7 @@ class InvalidTokenError < RuntimeError; end
47
41
# is set and `credential_path` is not set.
48
42
# @option options [String] :credential_path By default, the value of the
49
43
# AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variable.
50
- # @option options [String] :endpoint The container credential endpoint.
44
+ # @option options [String] :endpoint The ECS credential endpoint.
51
45
# By default, this is the value of the AWS_CONTAINER_CREDENTIALS_FULL_URI
52
46
# environment variable. This value is ignored if `credential_path` or
53
47
# ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] is set.
@@ -70,6 +64,7 @@ def initialize(options = {})
70
64
endpoint = options [ :endpoint ] ||
71
65
ENV [ 'AWS_CONTAINER_CREDENTIALS_FULL_URI' ]
72
66
initialize_uri ( options , credential_path , endpoint )
67
+ @authorization_token = ENV [ 'AWS_CONTAINER_AUTHORIZATION_TOKEN' ]
73
68
74
69
@retries = options [ :retries ] || 5
75
70
@http_open_timeout = options [ :http_open_timeout ] || 5
@@ -108,43 +103,31 @@ def initialize_relative_uri(options, path)
108
103
109
104
def initialize_full_uri ( endpoint )
110
105
uri = URI . parse ( endpoint )
111
- validate_full_uri_scheme! ( uri )
112
106
validate_full_uri! ( uri )
113
- @host = uri . hostname
107
+ @host = uri . host
114
108
@port = uri . port
115
109
@scheme = uri . scheme
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"
110
+ @credential_path = uri . path
123
111
end
124
112
125
113
# Validate that the full URI is using a loopback address if scheme is http.
126
114
def validate_full_uri! ( full_uri )
127
115
return unless full_uri . scheme == 'http'
128
116
129
117
begin
130
- return if valid_ip_address ?( IPAddr . new ( full_uri . host ) )
118
+ return if ip_loopback ?( IPAddr . new ( full_uri . host ) )
131
119
rescue IPAddr ::InvalidAddressError
132
120
addresses = Resolv . getaddresses ( full_uri . host )
133
- return if addresses . all? { |addr | valid_ip_address ?( IPAddr . new ( addr ) ) }
121
+ return if addresses . all? { |addr | ip_loopback ?( IPAddr . new ( addr ) ) }
134
122
end
135
123
136
124
raise ArgumentError ,
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 )
125
+ 'AWS_CONTAINER_CREDENTIALS_FULL_URI must use a loopback ' \
126
+ 'address when using the http scheme.'
143
127
end
144
128
145
129
# loopback? method is available in Ruby 2.5+
146
130
# Replicate the logic here.
147
- # loopback (IPv4 127.0.0.0/8, IPv6 ::1/128)
148
131
def ip_loopback? ( ip_address )
149
132
case ip_address . family
150
133
when Socket ::AF_INET
@@ -156,20 +139,6 @@ def ip_loopback?(ip_address)
156
139
end
157
140
end
158
141
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
-
173
142
def backoff ( backoff )
174
143
case backoff
175
144
when Proc then backoff
@@ -205,36 +174,10 @@ def get_credentials
205
174
http_get ( conn , @credential_path )
206
175
end
207
176
end
208
- rescue TokenFileReadError , InvalidTokenError
209
- raise
210
177
rescue StandardError
211
178
'{}'
212
179
end
213
180
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
-
238
181
def open_connection
239
182
http = Net ::HTTP . new ( @host , @port , nil )
240
183
http . open_timeout = @http_open_timeout
@@ -247,27 +190,18 @@ def open_connection
247
190
248
191
def http_get ( connection , path )
249
192
request = Net ::HTTP ::Get . new ( path )
250
- set_authorization_token ( request )
193
+ request [ 'Authorization' ] = @authorization_token if @authorization_token
251
194
response = connection . request ( request )
252
195
raise Non200Response unless response . code . to_i == 200
253
196
254
197
response . body
255
198
end
256
199
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
-
264
200
def retry_errors ( error_classes , options = { } )
265
201
max_retries = options [ :max_retries ]
266
202
retries = 0
267
203
begin
268
204
yield
269
- rescue TokenFileReadError , InvalidTokenError
270
- raise
271
205
rescue *error_classes => _e
272
206
raise unless retries < max_retries
273
207
0 commit comments