-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(proxy): specify hosts for proxy exclusion instead of complete URLs #6957
base: main
Are you sure you want to change the base?
Conversation
Changed Files
|
@@ -623,7 +623,7 @@ pub struct Proxy { | |||
pub http_url: Option<String>, | |||
pub https_url: Option<String>, | |||
pub idle_pool_connection_timeout: Option<u64>, | |||
pub bypass_proxy_urls: Vec<String>, | |||
pub bypass_proxy_hosts: Option<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not using a Vec
or HashSet
here (and splitting the string on commas), we pass the string directly to NoProxy::from_string()
, which handles the splitting by comma and trimming whitespaces.
let proxy_exclusion_config = | ||
reqwest::NoProxy::from_string(&proxy_config.bypass_proxy_hosts.clone().unwrap_or_default()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using unwrap_or_default()
here, since NoProxy::from_string()
returns None
if the string is empty, and since Proxy::no_proxy()
accepts Option<NoProxy>
.
proxy_client: reqwest::Client, | ||
non_proxy_client: reqwest::Client, | ||
whitelisted_urls: Vec<String>, | ||
proxy_config: Proxy, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the proxy_config
field, which is required when constructing a client where certificates are specified.
pub fn new(proxy_config: &Proxy) -> CustomResult<Self, ApiClientError> { | ||
let client = get_client_builder(proxy_config)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this to call get_client_builder()
, since most of the code was duplicated.
(Some(certificate), Some(certificate_key)) => { | ||
let client_builder = | ||
reqwest::Client::builder().redirect(reqwest::redirect::Policy::none()); | ||
let client_builder = get_client_builder(&self.proxy_config)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this to call get_client_builder()
as well, since the get_reqwest_client()
method did not previously configure proxies for the ClientBuilder
.
Type of Change
Description
This PR refactors the logic for excluding specific HTTP / HTTPS traffic from being proxied via the outgoing proxy. Specifically, the changes included are:
This is achieved with
reqwest::Proxy::no_proxy()
andreqwest::NoProxy::from_string()
.Additional Changes
This PR introduces a config option
bypass_proxy_hosts
instead ofbypass_proxy_urls
under the[proxy]
config section.Motivation and Context
This would help significantly reduce maintenance efforts on our side with respect to which URLs we wanted to be excluded from being proxied, since we previously had some of these URLs being specified in code. The PR helps ensure that all the domains to be excluded would be specified via configuration alone, while also allowing us to easily exclude subdomains (for example, excluding
cluster.local
would exclude all traffic to services within a Kubernetes cluster from being proxied).Closes #1039.
How did you test it?
Locally, by setting up
mitmproxy
as a proxy for outgoing HTTP and HTTPS traffic. I also set up our card vault locally to simulate an internal service running close to the application.I ran
mitmproxy
using the command:Application was configured in the
development.toml
file to use the proxy:Creating a payment via Postman:
Two requests are listed on the
mitmproxy
web interface, one toapi.stripe.com
and one towebhook.site
, indicating that they were proxied. In this case, all HTTPS traffic is being proxied.Saving a payment method in the locker:
The locker host is initially configured as:
Since the locker host was
127.0.0.1
and onlylocalhost
was excluded from being proxied, the locker request is also being proxied:On updating the locker host to
http://localhost:3001
in thedevelopment.toml
file, the locker request is no longer proxied, themitmproxy
web interface is blank:As another confirmation that the locker call actually happened, I see logs emitted by the locker application with the same request ID as that returned by the
router
in its response headers.One more thing to note here is that we did not have to include the port number (
localhost:3001
) in thebypass_proxy_hosts
list, onlylocalhost
was sufficient.Excluding
stripe.com
from being proxied and creating a payment:I updated the
development.toml
file to includestripe.com
inbypass_proxy_hosts
:Even though we only excluded
stripe.com
and did not explicitly excludeapi.stripe.com
, the request toapi.stripe.com
was excluded as well. This can be compared with the screenshot in (1), the request toapi.stripe.com
is not listed:(2) and (3) indicate that proxy exclusion is happening as expected.
Testing on our hosted environments
In case of our hosted environments, we would have to ensure that nothing with respect to outgoing traffic from the
router
application remains affected: if an outgoing proxy has been configured (correctly), all of the external HTTP(S) traffic (to connectors, etc.) must be proxied, while traffic to our internal services such as our locker or encryption service must be excluded from being proxied.Checklist
cargo +nightly fmt --all
cargo clippy