class Aws::ECSCredentials
ec2 = Aws::EC2::Client.new(credentials: ecs_credentials)
ecs_credentials = Aws::ECSCredentials.new(retries: 3)
instances running in ECS.
An auto-refreshing credential provider that loads credentials from
def backoff(backoff)
def backoff(backoff) case backoff when Proc then backoff when Numeric then ->(_) { sleep(backoff) } else ->(num_failures) { Kernel.sleep(1.2**num_failures) } end end
def get_credentials
def get_credentials # Retry loading credentials a configurable number of times if # the instance metadata service is not responding. retry_errors(NETWORK_ERRORS, max_retries: @retries) do open_connection do |conn| http_get(conn, @credential_path) end end rescue StandardError '{}' end
def http_get(connection, path)
def http_get(connection, path) request = Net::HTTP::Get.new(path) request['Authorization'] = @authorization_token if @authorization_token response = connection.request(request) raise Non200Response unless response.code.to_i == 200 response.body end
def initialize(options = {})
(**options)
-
before_refresh
(Callable
) -- Proc called before -
:http_debug_output
(IO
) -- HTTP wire -
:delay
(Numeric, Proc
) -- By default, failures are retried -
:http_read_timeout
(Float
) -- -
:http_open_timeout
(Float
) -- -
:endpoint
(String
) -- The ECS credential endpoint. -
:credential_path
(String
) -- By default, the value of the -
:port
(Integer
) -- This value is ignored if `endpoint` -
:ip_address
(String
) -- This value is -
:retries
(Integer
) -- Number of times to retry
Parameters:
-
options
(Hash
) --
def initialize(options = {}) credential_path = options[:credential_path] || ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] endpoint = options[:endpoint] || ENV['AWS_CONTAINER_CREDENTIALS_FULL_URI'] initialize_uri(options, credential_path, endpoint) @authorization_token = ENV['AWS_CONTAINER_AUTHORIZATION_TOKEN'] @retries = options[:retries] || 5 @http_open_timeout = options[:http_open_timeout] || 5 @http_read_timeout = options[:http_read_timeout] || 5 @http_debug_output = options[:http_debug_output] @backoff = backoff(options[:backoff]) @async_refresh = false super end
def initialize_full_uri(endpoint)
def initialize_full_uri(endpoint) uri = URI.parse(endpoint) validate_full_uri!(uri) @host = uri.host @port = uri.port @scheme = uri.scheme @credential_path = uri.path end
def initialize_relative_uri(options, path)
def initialize_relative_uri(options, path) @host = options[:ip_address] || '169.254.170.2' @port = options[:port] || 80 @scheme = 'http' @credential_path = path end
def initialize_uri(options, credential_path, endpoint)
def initialize_uri(options, credential_path, endpoint) if credential_path initialize_relative_uri(options, credential_path) # Use FULL_URI/endpoint only if RELATIVE_URI/path is not set elsif endpoint initialize_full_uri(endpoint) else raise ArgumentError, 'Cannot instantiate an ECS Credential Provider '\ 'without a credential path or endpoint.' end end
def ip_loopback?(ip_address)
loopback? method is available in Ruby 2.5+
def ip_loopback?(ip_address) case ip_address.family when Socket::AF_INET ip_address & 0xff000000 == 0x7f000000 when Socket::AF_INET6 ip_address == 1 else false end end
def open_connection
def open_connection http = Net::HTTP.new(@host, @port, nil) http.open_timeout = @http_open_timeout http.read_timeout = @http_read_timeout http.set_debug_output(@http_debug_output) if @http_debug_output http.use_ssl = @scheme == 'https' http.start yield(http).tap { http.finish } end
def refresh
def refresh # Retry loading credentials up to 3 times is the instance metadata # service is responding but is returning invalid JSON documents # in response to the GET profile credentials call. retry_errors([Aws::Json::ParseError, StandardError], max_retries: 3) do c = Aws::Json.load(get_credentials.to_s) @credentials = Credentials.new( c['AccessKeyId'], c['SecretAccessKey'], c['Token'] ) @expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil end rescue Aws::Json::ParseError raise Aws::Errors::MetadataParserError end
def retry_errors(error_classes, options = {})
def retry_errors(error_classes, options = {}) max_retries = options[:max_retries] retries = 0 begin yield rescue *error_classes => _e raise unless retries < max_retries @backoff.call(retries) retries += 1 retry end end
def validate_full_uri!(full_uri)
def validate_full_uri!(full_uri) return unless full_uri.scheme == 'http' begin return if ip_loopback?(IPAddr.new(full_uri.host)) rescue IPAddr::InvalidAddressError addresses = Resolv.getaddresses(full_uri.host) return if addresses.all? { |addr| ip_loopback?(IPAddr.new(addr)) } end raise ArgumentError, 'AWS_CONTAINER_CREDENTIALS_FULL_URI must use a loopback '\ 'address when using the http scheme.' end