Skip to content

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

Merged
ggreenway merged 14 commits intoenvoyproxy:mainfrom
kyessenov:copy_response_headers
Sep 26, 2022
Merged

tcp tunneling: optionally move response header to downstream info#23118
ggreenway merged 14 commits intoenvoyproxy:mainfrom
kyessenov:copy_response_headers

Conversation

@kyessenov
Copy link
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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

// 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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

"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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Renamed.

@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
Copy Markdown
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
Copy Markdown
Contributor

/lgtm api

Copy link
Copy Markdown
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

[(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
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor

/lgtm api

alyssawilk
alyssawilk previously approved these changes Sep 22, 2022
Copy link
Copy Markdown
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
Copy Markdown
Member

@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
Copy Markdown
Member

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
Copy Markdown
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