-
Notifications
You must be signed in to change notification settings - Fork 4.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
Avoid panic applying TProxy Envoy extensions #17537
Conversation
f8b8034
to
8c30455
Compare
switch config.Kind { | ||
case api.ServiceKindTerminatingGateway: | ||
return b.patchTerminatingGatewayListenerFilterChains(config, l, nameOrSNI) | ||
case api.ServiceKindConnectProxy: | ||
return b.patchConnectProxyListenerFilterChains(config, l, nameOrSNI) | ||
} | ||
return l, nil | ||
} | ||
|
||
func (b *BasicEnvoyExtender) patchTerminatingGatewayListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener, nameOrSNI string) (*envoy_listener_v3.Listener, error) { | ||
var resultErr error | ||
for idx, filterChain := range l.FilterChains { | ||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, l); err == nil { | ||
l.FilterChains[idx] = patchedFilterChain | ||
} else { | ||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain of terminating gateway listener %q: %w", nameOrSNI, err)) | ||
} | ||
} | ||
|
||
return l, resultErr | ||
} | ||
|
||
func (b *BasicEnvoyExtender) patchConnectProxyListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener, nameOrSNI string) (*envoy_listener_v3.Listener, error) { | ||
if IsOutboundTProxyListener(l) { | ||
patchedListener, err := b.patchTProxyListenerFilterChains(config, l) | ||
if err == nil { | ||
return patchedListener, nil | ||
} else { | ||
return l, fmt.Errorf("error patching filter chain of TProxy listener %q: %w", nameOrSNI, err) | ||
} | ||
} else { | ||
|
||
patchedListener, err := b.patchNonTProxyConnectProxyListenerFilterChains(config, l) | ||
if err == nil { | ||
return patchedListener, nil | ||
} else { | ||
return l, fmt.Errorf("error patching filter chain of connect proxy listener %q: %w", nameOrSNI, err) | ||
} | ||
} | ||
} |
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.
All the filter chain patching code turned out to be identical except for the removed check for VIPs below (which is not necessary for the BasicEnvoyExtender
, because UpstreamEnvoyExtender
now handles extensions - Lambda and Validate - configured via an upstream of the local proxy).
func (b *BasicEnvoyExtender) patchTProxyListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, error) { | ||
var resultErr error | ||
|
||
vip := config.Upstreams[config.ServiceName].VIP |
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.
This line was the source of the panic. We wouldn't expect config.Upstreams[config.ServiceName]
to exist except if the local service has itself configured as an upstream; regardless, it's not necessary here.
Removing this check fixes the second regression in which TProxy filters were not patched by BasicEnvoyExtender
(Lua).
upstream := config.Upstreams[config.ServiceName] | ||
if upstream == nil { | ||
return l, false, nil | ||
} | ||
vip := upstream.VIP |
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.
Guards against the same bug without removing the VIP check, which is necessary in this case.
@@ -728,7 +728,7 @@ func TestConfigSnapshotTransparentProxyDestination(t testing.T) *ConfigSnapshot | |||
}) | |||
} | |||
|
|||
func TestConfigSnapshotTransparentProxyDestinationHTTP(t testing.T) *ConfigSnapshot { | |||
func TestConfigSnapshotTransparentProxyDestinationHTTP(t testing.T, nsFn func(ns *structs.NodeService)) *ConfigSnapshot { |
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.
This allows us to configure the Lua extension for the local service, which will target TProxy upstreams.
"name": "envoy.filters.http.lua", | ||
"typedConfig": { | ||
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua", | ||
"inlineCode": "\nfunction envoy_on_request(request_handle)\n request_handle:headers():add(\"test\", \"test\")\nend" | ||
} |
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.
Patched HTTP upstream 1/2
"name": "envoy.filters.http.lua", | ||
"typedConfig": { | ||
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua", | ||
"inlineCode": "\nfunction envoy_on_request(request_handle)\n request_handle:headers():add(\"test\", \"test\")\nend" | ||
} |
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.
Patched HTTP upstream 2/2
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.
This looks fine to me if you're certain that the removed code in the basic envoy extender wasn't needed for anything.
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.
Great work. I'm super glad that you caught this.
When UpstreamEnvoyExtender was introduced, some code was left duplicated between it and BasicEnvoyExtender. One path in that code panics when a TProxy listener patch is attempted due to no upstream data in RuntimeConfig matching the local service (which would only happen in rare cases). Instead, we can remove the special handling of upstream VIPs from BasicEnvoyExtender entirely, greatly simplifying the listener filter patch code and avoiding the panic. UpstreamEnvoyExtender, which needs this code to function, is modified to ensure a panic does not occur. This also fixes a second regression in which the Lua extension was not applied to TProxy outbound listeners.
8c30455
to
c66703f
Compare
func (b *BasicEnvoyExtender) patchListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener, nameOrSNI string) (*envoy_listener_v3.Listener, error) { | ||
func (b *BasicEnvoyExtender) patchSupportedListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener, nameOrSNI string) (*envoy_listener_v3.Listener, error) { | ||
switch config.Kind { | ||
case api.ServiceKindTerminatingGateway: | ||
return b.patchTerminatingGatewayListenerFilterChains(config, l, nameOrSNI) | ||
case api.ServiceKindConnectProxy: | ||
return b.patchConnectProxyListenerFilterChains(config, l, nameOrSNI) | ||
case api.ServiceKindTerminatingGateway, api.ServiceKindConnectProxy: | ||
return b.patchListenerFilterChains(config, l, nameOrSNI) |
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.
After double checking the original change that introduced this switch and the matching one above, I restored it to align with that and reduce changes here (I'd originally thought it was more copy-pasta). This could prevent a future bug if we were to support more proxy types for extensions in general without aligning that support with listeners specifically.
No other changes since the last review. I've also re-tested by hand w/ this change.
When
UpstreamEnvoyExtender
was introduced, some code was left duplicated between it andBasicEnvoyExtender
. One path in that code panics when a TProxy listener patch is attempted due to no upstream data inRuntimeConfig
matching the local service (which would only happen in rare cases).Instead, we can remove the special handling of upstream VIPs from
BasicEnvoyExtender
entirely, greatly simplifying the listener filter patch code and avoiding the panic.UpstreamEnvoyExtender
, which needs this code to function, is modified to ensure a panic does not occur.This also fixes a second regression in which the Lua extension was not applied to TProxy outbound listeners.
Description
This fixes two regressions caused by #17415.
Testing & Reproduction steps
I've hand-tested this fix in addition to adding tests to guard against the regressions.
PR Checklist