class Aws::InstanceProfileCredentials

def _metadata_disabled?

def _metadata_disabled?
  ENV.fetch('AWS_EC2_METADATA_DISABLED', 'false').downcase == 'true'
end

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.
  if _metadata_disabled?
    '{}'
  else
    begin
      retry_errors(NETWORK_ERRORS, max_retries: @retries) do
        open_connection do |conn|
          # attempt to fetch token to start secure flow first
          # and rescue to failover
          begin
            retry_errors(NETWORK_ERRORS, max_retries: @retries) do
              unless token_set?
                token_value, ttl = http_put(
                  conn, METADATA_TOKEN_PATH, @token_ttl
                )
                @token = Token.new(token_value, ttl) if token_value && ttl
              end
            end
          rescue *NETWORK_ERRORS
            # token attempt failed, reset token
            # fallback to non-token mode
            @token = nil
          end
          token = @token.value if token_set?
          metadata = http_get(conn, METADATA_PATH_BASE, token)
          profile_name = metadata.lines.first.strip
          http_get(conn, METADATA_PATH_BASE + profile_name, token)
        end
      end
    rescue
      '{}'
    end
  end
end

def http_get(connection, path, token = nil)

GET request fetch profile and credentials
def http_get(connection, path, token = nil)
  headers = { 'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}" }
  headers['x-aws-ec2-metadata-token'] = token if token
  response = connection.request(Net::HTTP::Get.new(path, headers))
  raise Non200Response unless response.code.to_i == 200
  response.body
end

def http_put(connection, path, ttl)

PUT request fetch token with ttl
def http_put(connection, path, ttl)
  headers = {
    'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}",
    'x-aws-ec2-metadata-token-ttl-seconds' => ttl.to_s
  }
  response = connection.request(Net::HTTP::Put.new(path, headers))
  case response.code.to_i
  when 200
    [
      response.body,
      response.header['x-aws-ec2-metadata-token-ttl-seconds'].to_i
    ]
  when 400
    raise TokenRetrivalError
  when 401
    raise TokenExpiredError
  else
    raise Non200Response
  end
end

def initialize(options = {})

Options Hash: (**options)
  • :token_ttl (Integer) -- Time-to-Live in seconds for EC2
  • :http_debug_output (IO) -- HTTP wire
  • :delay (Numeric, Proc) -- By default, failures are retried
  • :http_read_timeout (Float) --
  • :http_open_timeout (Float) --
  • :port (Integer) --
  • :ip_address (String) --
  • :retries (Integer) -- Number of times to retry

Parameters:
  • options (Hash) --
def initialize(options = {})
  @retries = options[:retries] || 1
  @ip_address = options[:ip_address] || '169.254.169.254'
  @port = options[:port] || 80
  @http_open_timeout = options[:http_open_timeout] || 1
  @http_read_timeout = options[:http_read_timeout] || 1
  @http_debug_output = options[:http_debug_output]
  @backoff = backoff(options[:backoff])
  @token_ttl = options[:token_ttl] || 21_600
  @token = nil
  super
end

def open_connection

def open_connection
  http = Net::HTTP.new(@ip_address, @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.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.
  begin
    retry_errors([JSON::ParserError, StandardError], max_retries: 3) do
      c = JSON.parse(get_credentials.to_s)
      @credentials = Credentials.new(
        c['AccessKeyId'],
        c['SecretAccessKey'],
        c['Token']
      )
      @expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil
    end
  rescue JSON::ParserError
    raise Aws::Errors::MetadataParserError
  end
end

def retry_errors(error_classes, options = {}, &_block)

def retry_errors(error_classes, options = {}, &_block)
  max_retries = options[:max_retries]
  retries = 0
  begin
    yield
  rescue *error_classes
    raise unless retries < max_retries
    @backoff.call(retries)
    retries += 1
    retry
  end
end

def token_set?

def token_set?
  @token && !@token.expired?
end