Skip to content

Commit

Permalink
Ignore proxy for cloud metadata retrieval
Browse files Browse the repository at this point in the history
Prior to this commit when a user set the http_proxy environment
variable, the Net::HTTP#new in the HTTP resolver would use it when
establishing new connections. While this is the desired behavior in
most cases, this also interfered with fetching cloud metadata for
services like AWS and GCP.

Facter had previously dealt with this behavior in earlier versions (2.x)
starting with 23bf7e5, but that was lost during Facter's transition to
C++ then back to Ruby.

This commit exposes Net::HTTP#new's p_addr (proxy address) argument and,
by necessity, the preceding port positional argument, and configures
both the AWS and GCE resolvers to always pass nil as the proxy address.
  • Loading branch information
mhashizume committed Apr 8, 2024
1 parent b732401 commit e33a9bc
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 11 deletions.
2 changes: 1 addition & 1 deletion lib/facter/resolvers/ec2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def build_path_component(line)
def get_data_from(url)
headers = {}
headers['X-aws-ec2-metadata-token'] = v2_token if v2_token
Facter::Util::Resolvers::Http.get_request(url, headers, { session: determine_session_timeout })
Facter::Util::Resolvers::Http.get_request(url, headers, { session: determine_session_timeout }, http_port: nil, proxy_addr: nil)
end

def determine_session_timeout
Expand Down
2 changes: 1 addition & 1 deletion lib/facter/resolvers/gce.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def read_facts(fact_name)
end

def query_for_metadata
gce_data = extract_to_hash(Facter::Util::Resolvers::Http.get_request(METADATA_URL, HEADERS))
gce_data = extract_to_hash(Facter::Util::Resolvers::Http.get_request(METADATA_URL, HEADERS, http_port: nil, proxy_addr: nil))
parse_instance(gce_data)

gce_data.empty? ? nil : gce_data
Expand Down
32 changes: 23 additions & 9 deletions lib/facter/util/resolvers/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,45 @@ module Http
class << self
CONNECTION_TIMEOUT = 0.6
SESSION_TIMEOUT = 5
DEFAULT_HOST = Object.new.freeze

# Makes a GET HTTP request and returns its response.
#
# @note This method uses an empty DEFAULT_HOST constant to provide a
# way to override the http_proxy environment variable without
# interfering with other behaviors (such as connecting to a
# loopback address or using the no_proxy environment variable).
# @param url [String] the address to which the request will be made.
# @param headers [Hash] the headers you need to add to your request.
# Defaults to an empty hash.
# @param timesouts [Hash] Values for the session and connection
# timeouts.
# @param http_port [Integer] The port number used to make the
# request. Defaults to 80.
# @param proxy_addr [String] The address of a proxy host.
# @returns [String] the response body if the response code is 200.
# If the response code is not 200, an empty string is returned.
# @example
# get_request(https://example.com, { "Accept": 'application/json' }, { session: 2.4. connection: 5 })
def get_request(url, headers = {}, timeouts = {})
make_request(url, headers, timeouts, 'GET')
def get_request(url, headers = {}, timeouts = {}, http_port: 80, proxy_addr: DEFAULT_HOST)
make_request(url, headers, timeouts, 'GET', http_port, proxy_addr)
end

# Makes a PUT HTTP request and returns its response
# @param (see #get_request)
# @return (see #get_request)
def put_request(url, headers = {}, timeouts = {})
make_request(url, headers, timeouts, 'PUT')
def put_request(url, headers = {}, timeouts = {}, http_port: 80, proxy_addr: DEFAULT_HOST)
make_request(url, headers, timeouts, 'PUT', http_port, proxy_addr)
end

private

def make_request(url, headers, timeouts, request_type)
# rubocop:disable Metrics/ParameterLists
def make_request(url, headers, timeouts, request_type, http_port, proxy_addr)
require 'net/http'

uri = URI.parse(url)
http = http_obj(uri, timeouts)
http = http_obj(uri, timeouts, http_port, proxy_addr)
request = request_obj(headers, uri, request_type)

# The Windows implementation of sockets does not respect net/http
Expand All @@ -56,9 +65,14 @@ def make_request(url, headers, timeouts, request_type)
@log.debug("Trying to connect to #{url} but got: #{e.message}")
''
end

def http_obj(parsed_url, timeouts)
http = Net::HTTP.new(parsed_url.host)
# rubocop:enable Metrics/ParameterLists

def http_obj(parsed_url, timeouts, http_port, proxy_addr)
http = if proxy_addr == DEFAULT_HOST
Net::HTTP.new(parsed_url.host)
else
Net::HTTP.new(parsed_url.host, http_port, proxy_addr)
end
http.read_timeout = timeouts[:session] || SESSION_TIMEOUT
http.open_timeout = timeouts[:connection] || CONNECTION_TIMEOUT

Expand Down

0 comments on commit e33a9bc

Please sign in to comment.