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

hcm: add match_upstream to SchemeHeaderTransformation #34099

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

wtzhang23
Copy link

@wtzhang23 wtzhang23 commented May 11, 2024

Commit Message: add match_upstream to SchemeHeaderTransformation
Additional Description: Define a new variant that configures the hcm to override the scheme with the upstream transport protocol. The value is accessible by all downstream filters and is specifically used by the Router filter. Renamed variant from use_upstream_scheme to be clear that the scheme matches the transport protocol.
Risk Level: low
Testing: unit testing
Docs Changes: n/a
Release Notes: n/a
Platform Specific Features: n/a
Fixes #33020

Copy link

Hi @wtzhang23, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #34099 was opened by wtzhang23.

see: more, trace.

Copy link

As a reminder, PRs marked as draft will not be automatically assigned reviewers,
or be handled by maintainer-oncall triage.

Please mark your PR as ready when you want it to be reviewed!

🐱

Caused by: #34099 was opened by wtzhang23.

see: more, trace.

Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @adisuissa
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #34099 was opened by wtzhang23.

see: more, trace.

@wtzhang23
Copy link
Author

wtzhang23 commented May 11, 2024

Small Qs:

  • Not familiar with the async client implementation. Is it possible that especially the gRPC client may take advantage of these settings?
  • What setting should the Admin interface use? I have it set to true which from my understanding will be a no-op.
  • Pass the should_match_upstream as a constructor param or keep using a setter in StreamInfo?

Signed-off-by: William <wtzhang23@gmail.com>
@wtzhang23
Copy link
Author

/retest

Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
High-level API comment, but otherwise API LGTM.

api/envoy/config/core/v3/protocol.proto Outdated Show resolved Hide resolved
Signed-off-by: William <wtzhang23@gmail.com>
Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
Please also add a release note.
/assign-from @envoyproxy/senior-maintainers

source/common/http/async_client_impl.cc Outdated Show resolved Hide resolved
source/server/admin/admin.h Outdated Show resolved Hide resolved
test/common/http/conn_manager_impl_test_2.cc Outdated Show resolved Hide resolved
@@ -4210,5 +4210,63 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamTimingsRecordWhenRequestHeaderPr
filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose);
}

TEST_F(HttpConnectionManagerImplTest, PassMatchUpstreamSchemeHintToStreamInfo) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High-level comment:
it seems that the relevant part of the test is essentially:
EXPECT_TRUE(filter->callbacks_->streamInfo().shouldSchemeMatchUpstream());

Can this test be refactored to minimize the non-relevant parts?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cut as much of the test as I'm familiar with. Will need to dive deeper to see if any other cuts can be made.

@@ -235,6 +236,7 @@ class HttpConnectionManagerImplMixin : public ConnectionManagerConfig {
HttpConnectionManagerProto::ServerHeaderTransformation server_transformation_{
HttpConnectionManagerProto::OVERWRITE};
absl::optional<std::string> scheme_;
bool scheme_match_upstream_{false};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: If this is not being overwritten, consider converting to const.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need this to be non-const to override in the PassMatchUpstreamSchemeHintToStreamInfo test I wrote.

Copy link

@envoyproxy/senior-maintainers assignee is @htuch

🐱

Caused by: a #34099 (review) was submitted by @adisuissa.

see: more, trace.

…compat

Signed-off-by: William <wtzhang23@gmail.com>
Signed-off-by: William <wtzhang23@gmail.com>
Signed-off-by: William <wtzhang23@gmail.com>
Signed-off-by: William <wtzhang23@gmail.com>
@wtzhang23
Copy link
Author

/retest

@htuch htuch assigned alyssawilk and unassigned htuch May 14, 2024
@htuch
Copy link
Member

htuch commented May 14, 2024

Reassigning to @alyssawilk for data plane senior maintainer coverage.

Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this version is cleaner, thanks for being willing to move over to it!
/wait on comments

// request be sent to the upstream over TLS, the scheme header will be set to "https". Should the
// request be sent over plaintext, the scheme header will be set to "http".
// If scheme_to_overwrite is set, this field is not used.
bool match_upstream = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have to have this separate can we instead reject config if both are set?

Copy link
Author

@wtzhang23 wtzhang23 May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too familiar with how validation of configs is done but my understanding is it uses protoc-gen-validate and I'm not sure if that schema supports cross-field rules? Could you guide me on where in the code base validation occurs to add this change? Looked through the code base for other examples and it seems throwing an exception is how this is done.

FWIW I do have a warning log present already. But agree it might be worthwhile to not fail silently.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously Envoy would've rejected the config. However, the issue is supporting both old and new Envoy binaries that use the same server. The server may want to set the new field for the new Envoys, but have the old field set for the old ones. That is why precedence was preferred over rejection.

That said, in the current case the new field does not take precedence over the old one, so it is less of an issue.

Copy link
Author

@wtzhang23 wtzhang23 May 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just use oneof then since this new field doesn't take precedence so if a user wants to use this field they have to not set the other field? Think I'd prefer this as a user rather than an exception, even if it violates the style guide. Especially since those that maintain/debug the data plane may not necessarily be those that own the control plane.

@@ -116,6 +116,7 @@ AsyncStreamImpl::AsyncStreamImpl(AsyncClientImpl& parent, AsyncClient::StreamCal
stream_info_.dynamicMetadata().MergeFrom(options.metadata);
stream_info_.setIsShadow(options.is_shadow);
stream_info_.setUpstreamClusterInfo(parent_.cluster_);
stream_info_.setShouldSchemeMatchUpstream(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooc isn't this just setting it to the default? Why not remove?

@@ -978,5 +978,33 @@ TEST_F(RouterTestSupressGRPCStatsDisabled, IncludeHttpTimeoutStats) {
.value());
}

class RouterTestSchemeMatchUpstream : public RouterTestBase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you need to subclass? Can't you just put the expect_call in your test body?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed new class and moved code to router.cc where all the tests that use RouterTest live.

@@ -124,7 +124,17 @@ uint64_t FilterUtility::percentageOfTimeout(const std::chrono::milliseconds resp
return static_cast<uint64_t>(response_time.count() * TimeoutPrecisionFactor / timeout.count());
}

void FilterUtility::setUpstreamScheme(Http::RequestHeaderMap& headers, bool downstream_secure) {
void FilterUtility::setUpstreamScheme(Http::RequestHeaderMap& headers, bool downstream_secure,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so there's a difference in what we pass in here
I think we need to decide if we want to set scheme based on "is upstream ssl" or "is upstream secure"
e.g. ALTS is secure but not TLS

Copy link
Author

@wtzhang23 wtzhang23 May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the golang grpc and alts source code, it seems like this should only be set when the upstream is using TLS and not ATLS. The RFC also seems to couple it with TLS.

Given the number of transport sockets, I'm thinking of adding a new virtual method to the transport socket to allow each socket to select which scheme it would like to set. Let me know if you have any opinions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to keep it simple and just check if it has an SSL context (TLS) to set the scheme to https, otherwise use http.

string scheme_to_overwrite = 1 [(validate.rules).string = {in: "http" in: "https"}];
}

// Set the Scheme header to match the upstream transport protocol. For example, should a
// request be sent to the upstream over TLS, the scheme header will be set to "https". Should the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment doesn't match code as commented below. Do we want to set ssl over secure transports or only over TLS?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to set it only over TLS to be consistent with the downstream fallback, which also only sets it if ssl_connection is not null.

Signed-off-by: William <wtzhang23@gmail.com>
Signed-off-by: William <wtzhang23@gmail.com>
…tocol test

Signed-off-by: William <wtzhang23@gmail.com>
Signed-off-by: William <wtzhang23@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add variant to SchemeHeaderTransformation to set scheme based on upstream transport
4 participants