66
77module Aws
88 # An auto-refreshing credential provider that loads credentials from
9- # instances running in containers .
9+ # instances running in ECS .
1010 #
1111 # ecs_credentials = Aws::ECSCredentials.new(retries: 3)
1212 # ec2 = Aws::EC2::Client.new(credentials: ecs_credentials)
@@ -17,12 +17,6 @@ class ECSCredentials
1717 # @api private
1818 class Non200Response < RuntimeError ; end
1919
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-
2620 # These are the errors we trap when attempting to talk to the
2721 # instance metadata service. Any of these imply the service
2822 # is not present, no responding or some other non-recoverable
@@ -47,7 +41,7 @@ class InvalidTokenError < RuntimeError; end
4741 # is set and `credential_path` is not set.
4842 # @option options [String] :credential_path By default, the value of the
4943 # 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.
5145 # By default, this is the value of the AWS_CONTAINER_CREDENTIALS_FULL_URI
5246 # environment variable. This value is ignored if `credential_path` or
5347 # ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] is set.
@@ -70,6 +64,7 @@ def initialize(options = {})
7064 endpoint = options [ :endpoint ] ||
7165 ENV [ 'AWS_CONTAINER_CREDENTIALS_FULL_URI' ]
7266 initialize_uri ( options , credential_path , endpoint )
67+ @authorization_token = ENV [ 'AWS_CONTAINER_AUTHORIZATION_TOKEN' ]
7368
7469 @retries = options [ :retries ] || 5
7570 @http_open_timeout = options [ :http_open_timeout ] || 5
@@ -108,43 +103,31 @@ def initialize_relative_uri(options, path)
108103
109104 def initialize_full_uri ( endpoint )
110105 uri = URI . parse ( endpoint )
111- validate_full_uri_scheme! ( uri )
112106 validate_full_uri! ( uri )
113- @host = uri . hostname
107+ @host = uri . host
114108 @port = uri . port
115109 @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
123111 end
124112
125113 # Validate that the full URI is using a loopback address if scheme is http.
126114 def validate_full_uri! ( full_uri )
127115 return unless full_uri . scheme == 'http'
128116
129117 begin
130- return if valid_ip_address ?( IPAddr . new ( full_uri . host ) )
118+ return if ip_loopback ?( IPAddr . new ( full_uri . host ) )
131119 rescue IPAddr ::InvalidAddressError
132120 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 ) ) }
134122 end
135123
136124 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.'
143127 end
144128
145129 # loopback? method is available in Ruby 2.5+
146130 # Replicate the logic here.
147- # loopback (IPv4 127.0.0.0/8, IPv6 ::1/128)
148131 def ip_loopback? ( ip_address )
149132 case ip_address . family
150133 when Socket ::AF_INET
@@ -156,20 +139,6 @@ def ip_loopback?(ip_address)
156139 end
157140 end
158141
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-
173142 def backoff ( backoff )
174143 case backoff
175144 when Proc then backoff
@@ -205,36 +174,10 @@ def get_credentials
205174 http_get ( conn , @credential_path )
206175 end
207176 end
208- rescue TokenFileReadError , InvalidTokenError
209- raise
210177 rescue StandardError
211178 '{}'
212179 end
213180
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-
238181 def open_connection
239182 http = Net ::HTTP . new ( @host , @port , nil )
240183 http . open_timeout = @http_open_timeout
@@ -247,27 +190,18 @@ def open_connection
247190
248191 def http_get ( connection , path )
249192 request = Net ::HTTP ::Get . new ( path )
250- set_authorization_token ( request )
193+ request [ 'Authorization' ] = @authorization_token if @authorization_token
251194 response = connection . request ( request )
252195 raise Non200Response unless response . code . to_i == 200
253196
254197 response . body
255198 end
256199
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-
264200 def retry_errors ( error_classes , options = { } )
265201 max_retries = options [ :max_retries ]
266202 retries = 0
267203 begin
268204 yield
269- rescue TokenFileReadError , InvalidTokenError
270- raise
271205 rescue *error_classes => _e
272206 raise unless retries < max_retries
273207
0 commit comments