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

tcp tunneling: optionally move response header to downstream info #23118

Merged
merged 14 commits into from
Sep 26, 2022

Conversation

kyessenov
Copy link
Contributor

@kyessenov kyessenov commented Sep 15, 2022

Signed-off-by: Kuat Yessenov kuat@google.com

Commit Message: Add support to save response headers from CONNECT tunnels in tcp_proxy. Fixes #23116
Additional Description: The use case is saving "baggage" header which provides additional metadata about the upstream endpoint for telemetry purposes.
Risk Level: low (opt-in)
Testing: unit, integration
Docs Changes: none
Release Notes: yes

Signed-off-by: Kuat Yessenov <kuat@google.com>
@repokitteh-read-only
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 @markdroth
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #23118 was opened by kyessenov.

see: more, trace.

Signed-off-by: Kuat Yessenov <kuat@google.com>
Signed-off-by: Kuat Yessenov <kuat@google.com>
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.

Thanks for picking this up!
Now that I think about it this could be useful for the http11 connect filter: @Augustyniak was just writing an EM integraion test which added to CONNECT response headers and there was no way to validate them elsewhere. If we end up sticking with per-header-name configuration I think it may be worth defining the message somewhere in the base codec protos rather than in the tcp proxy proto for eventual reuse.
/wait

@@ -166,6 +166,7 @@ class HttpUpstream : public GenericUpstream, protected Http::StreamCallbacks {
// Http::ResponseDecoder
void decode1xxHeaders(Http::ResponseHeaderMapPtr&&) override {}
void decodeHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) override {
parent_.config_.copyResponseHeaders(*headers, parent_.downstream_info_.filterState());
Copy link
Contributor

Choose a reason for hiding this comment

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

Once we finish this function, don't we largely throw the headers away?
Would it make sense just to move the entire headers in the filter, with a well known name, rather than coping one bit of metadata at a time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I think we could do that with little performance impact. One annoying issue is that we don't have a generic way to traverse the filter state that is a map of string to string. That latter issue has been a long standing blocker for replacing dynamic metadata with filter state so maybe we should just fix that as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

do we need a map of string to string? we could just create a filter state object "connect_headers" which we std::move the headers into?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's what I want to do. But then, for example, access log printers can only print it as a whole. It's not a problem for internal filter consumption, just generic inspectors like access log, etc.

// Defines the mapping from the header value to a filter state object key.
message HeaderToFilterState {
// Filter state object key, prefixed with ``envoy.tcp_proxy.tunnel_response_header.``.
string key = 1 [(validate.rules).string = {min_len: 1}];
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 do with putting in individual headers, is there value in being able to configure the key rather than just sticking header name at the end of the string?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll try a complete bag copy, and in that case we can use one key for all of them.

@@ -68,6 +68,16 @@ message TcpProxy {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.network.tcp_proxy.v2.TcpProxy.TunnelingConfig";

// Defines the mapping from the header value to a filter state object key.
message HeaderToFilterState {
Copy link
Contributor

Choose a reason for hiding this comment

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

probably want a release note for this one once we've settled on API

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Signed-off-by: Kuat Yessenov <kuat@google.com>
Signed-off-by: Kuat Yessenov <kuat@google.com>
Signed-off-by: Kuat Yessenov <kuat@google.com>
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.

/wait


// Emit response headers to the downstream info filter state for consumption
// by the network filters. The filter state key is ``envoy.tcp_proxy.tunnel_response_headers``.
bool emit_response_headers = 4;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd lean towards something akin to
save_connect_headers but I'll defer to api shephards on this one :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@markdroth For API review and deciding on naming.

Copy link
Contributor

Choose a reason for hiding this comment

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

How about calling this propagate_response_headers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed.

source/common/router/router.h Outdated Show resolved Hide resolved
@kyessenov kyessenov changed the title tcp tunneling: copy response header to downstream info tcp tunneling: optionally move response header to downstream info Sep 19, 2022
alyssawilk
alyssawilk previously approved these changes Sep 20, 2022
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.

LGTM (though I still don't love emit - @markdroth ?)
Passing to Greg for !google pass

Signed-off-by: Kuat Yessenov <kuat@google.com>
@markdroth
Copy link
Contributor

/lgtm api

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.

Yeah I like this better - thanks for your patience with naming
CI looks unhappy?
/wait

@@ -99,6 +99,10 @@ message TcpProxy {
// Neither ``:-prefixed`` pseudo-headers nor the Host: header can be overridden.
repeated config.core.v3.HeaderValueOption headers_to_add = 3
[(validate.rules).repeated = {max_items: 1000}];

// Save the response headers to the downstream info filter state for consumption
// by the network filters. The filter state key is ``envoy.tcp_proxy.tunnel_response_headers``.
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe make the key propagate as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@@ -223,6 +223,11 @@ new_features:
- area: redis
change: |
added support for quit command to the redis proxy.
- area: tcp_proxy
change: |
added support for emitting the response headers in :ref:`TunnelingConfig
Copy link
Contributor

Choose a reason for hiding this comment

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

emitting -> propagating ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Signed-off-by: Kuat Yessenov <kuat@google.com>
@markdroth
Copy link
Contributor

/lgtm api

alyssawilk
alyssawilk previously approved these changes Sep 22, 2022
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.

over to @ggreenway !

Copy link
Contributor

@ggreenway ggreenway left a comment

Choose a reason for hiding this comment

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

Please add a test validating that headers are not propagated when the new setting is disabled.

/wait


// Save the response headers to the downstream info filter state for consumption
// by the network filters. The filter state key is ``envoy.tcp_proxy.propagate_response_headers``.
bool propagate_response_headers = 4;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not do this unconditionally? Performance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, for long-living streams, we're adding extra memory per stream since the filter state lives till connection closes.

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

Successfully merging this pull request may close these issues.

tcp_proxy: save response headers for CONNECT upstreams
4 participants