Skip to content
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

Add withDefaultRequestConfigCustomizer method to HttpComponentsClientHttpRequestFactoryBuilder #43139

Closed
oyvindhorneland opened this issue Nov 13, 2024 · 13 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@oyvindhorneland
Copy link

oyvindhorneland commented Nov 13, 2024

Apache HttpClient 5.4.x (in upcoming Spring Boot 3.4) has by default enabled HTTP/1.1 TLS Upgrade in apache/httpcomponents-client#542. This causes an issue for k8s deployments using Istio service mesh (and Envoy proxies) as described in istio/istio#53239 where outbound http requests will receive a HTTP status 403 with "upgrade_failed".

The issue has been reported to the Apache project in https://issues.apache.org/jira/browse/HTTPCLIENT-2344, where it has been closed as invalid since they believe Envoy is not behaving correctly.

The issue has been reported to Envoy in envoyproxy/envoy#36305 where discussions are ongoing.

Note that the protocol upgrade is only enabled for OPTIONS, HEAD and GET requests and clients may therefore observe that some requests work and others don't (Envoy will block the ones containing the TLS upgrade headers).

Code based workaround is to change protocolUpgradeEnabled to false when creating the HttpClient's RequestConfig.

        RequestConfig requestConfig = RequestConfig.custom()
                // ...
                .setProtocolUpgradeEnabled(false)
                .build();
        HttpClient httpClient = HttpClientBuilder.create()
                // ...
                .setDefaultRequestConfig(requestConfig)
                .build();

There is currently no system property in Apache HttpClient5 to disable protocolUpgradeEnable.

Should this known issue and possible workarounds be listed in the migration guide?

Not sure if a configuration option is a good possibility here, but HttpComponentsClientHttpRequestFactory will currently by default try to use HttpClients.createSystem() with protocolUpgrade enabled by default.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 13, 2024
@nosan
Copy link
Contributor

nosan commented Nov 13, 2024

A possible workaround is configuring your own ClientHttpRequestFactoryBuilder:

@Bean
public HttpComponentsClientHttpRequestFactoryBuilder httpComponentsClientHttpRequestFactoryBuilder() {
	return ClientHttpRequestFactoryBuilder.httpComponents()
			.withHttpClientCustomizer(this::disableProtocolUpgrade);
}

private void disableProtocolUpgrade(HttpClientBuilder builder) {
	builder.setDefaultRequestConfig(RequestConfig.custom()
			.setProtocolUpgradeEnabled(false)
			.build());
}

@oyvindhorneland
Copy link
Author

Thank you and yes, that is probably a better workaround if it affects all autoconfigured HttpClient instances.

@nosan
Copy link
Contributor

nosan commented Nov 13, 2024

if it affects all autoconfigured HttpClient instances.

The ClientHttpRequestFactoryBuilder is used by RestClientAutoConfiguration, RestTemplateAutoConfiguration, and WebServiceTemplateAutoConfiguration.

@philwebb philwebb self-assigned this Nov 13, 2024
@oyvindhorneland
Copy link
Author

Any thoughts on if the new default settings for Apache HttpClient's protocolUpgradeEnabled should be kept as a default in Spring Boot or if the default in Spring Boot should be to disable it or make it easy to configure it through a built-in configuration property? The reasoning in https://issues.apache.org/jira/browse/HTTPCLIENT-2344 argues for a secure and spec compliant default, but this change will also mean changing the behavior of outbound connections for existing apps and that some apps may break. And it currently looks like Envoy may continue being strict and keep rejecting it by default due to fear of security issues.

@philwebb
Copy link
Member

I think we should probably align with whatever defaults HttpClient provides. That's generally the rule that we try to follow. It's not ideal that there's a mismatch between what the HttpClient and Envoy maintainers consider sensible default behavior.

I'm not too keen to add a configuration property for this because we don't currently have any client specific properties. It would need to be something like spring.http.client.httpcomponents.protocol.upgrade.enabled=false. That then opens the door for a whole bunch of other properties being requested.

I do think we can make #43139 (comment) a little easier to apply if we tweak our code. Something like:

@Bean
public HttpComponentsClientHttpRequestFactoryBuilder httpComponentsClientHttpRequestFactoryBuilder() {
	return ClientHttpRequestFactoryBuilder.httpComponents()
			.withDefaultRequestConfigManagerCustomizer((builder) -> builder.setProtocolUpgradeEnabled(false));

I think we might have to do that as a first step and see what happens with https://issues.apache.org/jira/browse/HTTPCLIENT-2344 and envoyproxy/envoy#36305

@philwebb philwebb changed the title Apache HttpClient 5.4.x migration issue due to new support for upgrading to TLS Add withDefaultRequestConfigManagerCustomizer method to HttpComponentsClientHttpRequestFactoryBuilder Nov 13, 2024
@philwebb philwebb added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 13, 2024
@philwebb philwebb added this to the 3.4.x milestone Nov 13, 2024
@nosan
Copy link
Contributor

nosan commented Nov 13, 2024

Thanks @philwebb

Would it make sense to add a note in the migration guide as well, if feasible?

@philwebb
Copy link
Member

Good idea, I'll do that as well.

@philwebb philwebb modified the milestones: 3.4.x, 3.4.0 Nov 13, 2024
@rafalh
Copy link

rafalh commented Nov 20, 2024

Where did the "manager" word came from in withDefaultRequestConfigManagerCustomizer? I think it would be nicer to have it named withDefaultRequestConfigCustomizer

@wilkinsona wilkinsona reopened this Nov 20, 2024
@wilkinsona wilkinsona added the for: team-meeting An issue we'd like to discuss as a team to make progress label Nov 20, 2024
@wilkinsona wilkinsona changed the title Add withDefaultRequestConfigManagerCustomizer method to HttpComponentsClientHttpRequestFactoryBuilder Add withDefaultRequestConfigCustomizer method to HttpComponentsClientHttpRequestFactoryBuilder Nov 20, 2024
@wilkinsona wilkinsona removed the for: team-meeting An issue we'd like to discuss as a team to make progress label Nov 20, 2024
@philwebb
Copy link
Member

I think I made a mistake copy/pasting another property. Thanks for noticing @rafalh

@nosan
Copy link
Contributor

nosan commented Nov 20, 2024

@philwebb 😄

 * @param defaultRequestConfigManagerCustomizer the customizer to apply
	public HttpComponentsClientHttpRequestFactoryBuilder withDefaultRequestConfigCustomizer(
			Consumer<RequestConfig.Builder> **defaultRequestConfigManagerCustomizer**) {
		Assert.notNull(**defaultRequestConfigManagerCustomizer**,
				"'**defaultRequestConfigManagerCustomizer**' must not be null");

philwebb added a commit that referenced this issue Nov 20, 2024
@philwebb philwebb reopened this Nov 20, 2024
@philwebb
Copy link
Member

This issue is cursed 😂

@rafalh
Copy link

rafalh commented Nov 22, 2024

@philwebb It's definitely cursed :P You forgot to update Spring Boot 3.4 Release Notes. It still references withDefaultRequestConfigManagerCustomizer

@wilkinsona
Copy link
Member

Thanks, @rafalh. I've updated the release notes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

6 participants