-
Notifications
You must be signed in to change notification settings - Fork 688
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
Requests can be misrouted due to HTTP/2 Connection Coalescing under certain scenarios #1493
Comments
Thank you for the report. After investigation I'm not sure what steps we can take to address this. For the case where requests for A workaround could be to add a catch all http route for For the case where requests for |
Thanks Dave. Your analysis lines up with my understanding described in the issue.
^ My understanding is that Envoy should be responding with a 421 in this case, but it does not do that today due to envoyproxy/envoy#6767 As you say, the TCP scenario seems even worse. I am not sure if Envoy itself can do anything in this case. |
How could envoy respond 421? Bar is not a hostname registered with the http manager. More correctly there is not virtualhost record for bar in the RDS tables. |
After reading through envoyproxy/envoy#6767 (comment), my understanding is that Envoy would return a 421 if |
This table summarizes the behavior that occurs when mixing L7 IngressRoutes and TCP Proxy IngressRoutes, assuming wildcard certificates and a wildcard DNS entry is in play. The table shows the results of what happens when two requests are made to separate IngressRoutes. The first request is made to the IngressRoute on the left-most column, while the second request is made to the IngressRoute in the top row.
(1) L7 IngressRoute + TCP Proxy with TLS passthroughThe initial connection is opened to the L7 IngressRoute. Requests to the TCPProxy Ingressroute will fail with a 404. (2) L7 IngressRoute + TCP Proxy without TLS passthroughThe initial connection is opened to the L7 IngressRoute. Requests to the TCPProxy Ingressroute will fail with a 404. (3) TCP Proxy w/ TLS Passthrough + L7 IngressRouteThe initial connection is opened to the TCP Proxy IngressRoute. Requests to the L7 IngressRoute are misrouted to the TCP Proxy IngressRoute. (4) Two TCP Proxy w/ TLS PassthroughThe initial connection is opened to TCP Proxy IngressRoute 1. Requests to TCP Proxy IngressRoute 2 are misrouted to TCP Proxy IngressRoute 1. (5) TCP Proxy w/ TLS Passthrough + TCP Proxy without TLS PassthroughThe initial connection is opeend to the TCP Proxy IngressRoute with TLS passthrough. Requests to the other TCP Proxy IngressRoute are misrouted to the first TCP Proxy IngressRoute. |
Assigning to 0.15.1 for tracking purposes. |
Hello, I want to give an update for the watchers of this ticket. The short version is my interpretation of this issue has not changed since #1493 (comment). The longer version is there is a possibility of applying a partial workaround in Envoy but I am wary of promoting this as a solution as its effectiveness is entirely dependant on the percentage of virtual hosts handled in http mode vs the percentage in tcp proxy mode. The higher the latter, the less effective this workaround will be. Unless all connections are handled by envoy in http mode, this issue will be present. What I am proposing is
I don't see a way that we can address connections which were intended for envoy in http mode but are misdirected by the browser to an established connection in tcpproxy mode because Envoy is not able to interdict those requests because they are not in HTTP mode, don't go through Envoy's HTTP connection manager, and in the case where TCP passthrough is used, are still encrypted into and out of Envoy. |
Raising priority, since the 1.4 release means that all users of wildcard certificates will be affected by this problem. |
Probably should link in envoyproxy/envoy#6767 here as well, as it may help. Oops, it was linked in the initial comment, but this should ensure it's top-of-mind. |
TLS routes are specialized to a unique virtual hostname. However, if wildcard certificates are being used, browsers will aggressively coalesce and reuse server connections even when the full origin hostname doesn't match. This results on 404 responses because each TLS virtual host only has routes for one host. We can avoid this behaviour bleeding out to users by generating a 421 Misdirected Request response if the request authority doesn't match the FQDN of the virtual host. In this case, the browser is supposed to understand that the request wasn't processed and re-send it on a new connection. This fixes projectcontour#1493. Signed-off-by: James Peach <jpeach@vmware.com>
TLS routes are specialized to a unique virtual hostname. However, if wildcard certificates are being used, browsers will aggressively coalesce and reuse server connections even when the full origin hostname doesn't match. This results on 404 responses because each TLS virtual host only has routes for one host. We can avoid this behaviour bleeding out to users by generating a 421 Misdirected Request response if the request authority doesn't match the FQDN of the virtual host. In this case, the browser is supposed to understand that the request wasn't processed and re-send it on a new connection. This fixes projectcontour#1493. Signed-off-by: James Peach <jpeach@vmware.com>
TLS routes are specialized to a unique virtual hostname. However, if wildcard certificates are being used, browsers will aggressively coalesce and reuse server connections even when the full origin hostname doesn't match. This results on 404 responses because each TLS virtual host only has routes for one host. We can avoid this behaviour bleeding out to users by generating a 421 Misdirected Request response if the request authority doesn't match the FQDN of the virtual host. In this case, the browser is supposed to understand that the request wasn't processed and re-send it on a new connection. This fixes projectcontour#1493. Signed-off-by: James Peach <jpeach@vmware.com>
TLS routes are specialized to a unique virtual hostname. However, if wildcard certificates are being used, browsers will aggressively coalesce and reuse server connections even when the full origin hostname doesn't match. This results on 404 responses because each TLS virtual host only has routes for one host. We can avoid this behaviour bleeding out to users by generating a 421 Misdirected Request response if the request authority doesn't match the FQDN of the virtual host. In this case, the browser is supposed to understand that the request wasn't processed and re-send it on a new connection. This fixes projectcontour#1493. Signed-off-by: James Peach <jpeach@vmware.com>
TLS routes are specialized to a unique virtual hostname. However, if wildcard certificates are being used, browsers will aggressively coalesce and reuse server connections even when the full origin hostname doesn't match. This results on 404 responses because each TLS virtual host only has routes for one host. We can avoid this behaviour bleeding out to users by generating a 421 Misdirected Request response if the request authority doesn't match the FQDN of the virtual host. In this case, the browser is supposed to understand that the request wasn't processed and re-send it on a new connection. This fixes projectcontour#1493. Signed-off-by: James Peach <jpeach@vmware.com>
tl;dr: Browsers reuse connections when using HTTP/2. With certain IngressRoute configurations (Envoy configurations), requests can be routed to the wrong backend or produce puzzling 404s.
We believe the root cause to be a bug in Envoy that has an open issue here: envoyproxy/envoy#6767
What we observed
We noticed that requests destined for an application (let's call it
foo
) were being routed to another application (let's call itbar
).Interestingly, the misrouting would only happen if we accessed
bar
before trying to reachfoo
. That is, if we quit the browser, opened it again, and accessedfoo
without first accessingbar
, we would get routed tofoo
as expected. Once we accessedbar
, all future requests tofoo
would get misrouted tobar
.In addition, we noticed that the misrouting only happened when using Chrome as the client. Requests produced by Firefox and cURL were being routed properly.
The deployment configuration
*.platform.us-east.example.com
)foo
is exposed viafoo.platform.us-east.example.com
using a regular IngressRoute with TLS enabled. The certificate used for TLS is a wildcard cert for*.platform.us-east.example.com
.bar
is exposed using atcpproxy
IngressRoute with TLS passthrough enabled. The certificate used for TLS is a wildcard cert for*.platform.us-east.example.com
.Our understanding of the issue
Based on envoyproxy/envoy#6767 (comment), we believe the problem is caused due to the connection coalescing that happens in HTTP/2.
Once the browser opens the connection to
bar.platform.us-east.example.com
, it latches that connection to the Envoy listener/filter pair that is responsible for servingbar
. Future requests to other applications on the same wildcard DNS entry (e.g.foo.platform.us-east.example.com
) are sent over the same connection to the same Envoy listener/filter pair.Depending on which application is accessed first, we see different behavior:
App exposed over TCP Proxy with TLS passthrough is accessed first
https://bar.platform.us-east.example.com
ingress_https
listener on theenvoy.tcp_proxy
filter.https://foo.platform.us-east.example.com
ingress_https
listener on theenvoy.tcp_proxy
filter.bar
App exposed over HTTPS IngressRoute is accessed first
https://foo.platform.us-east.example.com
ingress_https
listener on theenvoy.http_connection_manager
filter.https://bar.platform.us-east.example.com
ingress_https
listener on theenvoy.http_connection_manager
filter.bar
is missing from the list of server names in theenvoy.http_connection_manager
filter chain.Repro steps
I've put together a set of Kubernetes deployment manifests that can be used to reproduce this issue with Contour. The apps are based on this comment (istio/istio#13589 (comment)).
The apps are:
index-application.yaml
: An nginx container listening for HTTPS connections. The TLS certificates are mounted into the container via a volume. Exposed using an IngressRoute with TLS passthrough.png-serving-application.yaml
: An nginx container listening for HTTP connections. An init container downloads a png into an emptyDir volume. The emptyDir volume is served by nginx. Exposed using a TLS-enabled IngressRoute.Repro steps:
Install contour
Apply application manifests
Open a tunnel to Envoy using kubectl (might need to use
sudo -E
to bind port 443)Verify both IngressRoutes are accessible with curl (Look for 200 response):
Browse to
https://app.127.0.0.1.nip.io
. Notice that the image does not load. If you open the browser's developer tools, you can see that the request for the image results in a 404.Browse to
https://image.127.0.0.1.nip.io
. Notice that the request is served by the index application.Open an incognito window and go to
https://image.127.0.0.1.nip.io/images/image.png
. Notice that the image is served as expected.Browse to
https://app.127.0.0.1.nip.io
in the incognito window. Notice that you get a 404 from Envoy.The text was updated successfully, but these errors were encountered: