Auto host rewrite option for strict_dns and logical_dns clusters#504
Auto host rewrite option for strict_dns and logical_dns clusters#504mattklein123 merged 19 commits intoenvoyproxy:masterfrom
Conversation
mattklein123
left a comment
There was a problem hiding this comment.
overall nice work, a few comments.
There was a problem hiding this comment.
nit: don't need the anchor if its not referenced anywhere (though you might want to reference from the router arch overview page).
There was a problem hiding this comment.
Yes, that is a todo on my end. Need to provide an example as well. Will add it to router arch
include/envoy/router/router.h
Outdated
There was a problem hiding this comment.
Though technically this should work (host:port), it's possible that some webservers might not handle this correctly. I could go either way, but my recommendation for now would be to remove hostAndPortFromTcpUrl() function that you added, and just populate the hostname() with the host, and without the port. Happy to discuss though.
There was a problem hiding this comment.
According to the RFC,
A "host" without any trailing port information implies the default port for the service requested (e.g., "80" for an HTTP URL).
I assumed that if its not a default port, then the port must be part of the Host header.
If stuff works without a port, I would be more than happy to reuse the hostFromTcpUrl function.
@kyessenov thoughts? You hit some issues in k8s regarding this right?
There was a problem hiding this comment.
yes, that's the RFC, but I'm just explaining that it might not actually work. In fact, Envoy is broken in this regard. We don't correctly parse out port when doing virtual host / domain matching from the host/auth header. For the use case you are adding this for, I strongly suspect that you probably only need host and not port, but you know your use case.
There was a problem hiding this comment.
My understanding is that envoy requires explicit port suffixes in hostname strings (e.g. domains in virtual hosts), just like RFC says.
I'd like to have the port number to be a part of the host rewrite string, and to be consistent with the server side config, it probably should be part of the string literal in the client cluster config. So basically, either strip port on both client and server side, or don't, but be consistent.
There was a problem hiding this comment.
There are 2 things being conflated here, how Envoy parses "URLs" and what a web/proxy server expects in the Host/:authority header. This change is about auto-populating the Host/:authority header. Technically, all web/proxy servers should support host:port when doing vhost, etc. matching, but that doesn't always work, and as I said above, Envoy itself is broken in this regard currently. I think you will have better luck with this feature if you just populate the DNS host name and skip the port.
There was a problem hiding this comment.
@kyessenov is this feature actually required for Istio? @rshriram I thought you were adding this to deal with cloud foundry.
There was a problem hiding this comment.
no, we just use host-rewrite (in ingress) and SDS.
There was a problem hiding this comment.
I would leave those 2 lines, they make sure the URL is well formed, which hostAndPortFromTcpUrl does not. Otherwise we might get an exception later on. Since it's probably not clear why these lines were here, please add a comment to that effect.
test/common/router/router_test.cc
Outdated
There was a problem hiding this comment.
The fact that this gets changed is an implementation detail that might not always be true. I would test that the headers you get in encodeHeaders() have the right host value. Same below.
|
Also, you probably saw, but your tests are failing with asserts enabled so you also need to fix that. |
|
Cloud foundry is the primary use case and I think you are right. Requests
hit the front end router at port 80, which then routes it to various CF
apps. In istio as well, this feature is useful when we want to use Envoy to
be the middleman between a kubernetes pod and a set of non-kubernetes
services (something like going out to the internet).
In both cases, as you point out, it's probably safer to stick to just the
dns name and not the port.
The use case Kuat talked about (and the reason I asked for his opinion) was
kubernetes internal traffic only. But now, i know the reason for why we
generate virtual hosts of the form mysvc.cluster.local:3350 -- Envoy
doesn't parse out the port in virtual hosts (not sure if it has to either
as per rfc).
On Wed, Feb 22, 2017 at 8:33 PM Matt Klein ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In source/common/upstream/logical_dns_cluster.cc
<#504 (comment)>:
> @@ -21,8 +21,7 @@ LogicalDnsCluster::LogicalDnsCluster(const Json::Object& config, Runtime::Loader
}
dns_url_ = hosts_json[0]->getString("url");
- Network::Utility::hostFromTcpUrl(dns_url_);
- Network::Utility::portFromTcpUrl(dns_url_);
+ hostname_ = Network::Utility::hostAndPortFromTcpUrl(dns_url_);
@kyessenov <https://github.com/kyessenov> is this feature actually
required for Istio? @rshriram <https://github.com/rshriram> I thought you
were adding this to deal with cloud foundry.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#504 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AH0qd8e0vT-uiZ57ktsedSnElbV7QKUiks5rfOIFgaJpZM4MJXQg>
.
--
~shriram
|
OK, for now, let's just stick with host name for the rewrite. If we need to revisit this later to add port info we can do that. |
4dced25 to
264d6f3
Compare
mattklein123
left a comment
There was a problem hiding this comment.
2 minor things otherwise looks good.
There was a problem hiding this comment.
nit: "... the DNS name ..."
test/common/router/router_test.cc
Outdated
There was a problem hiding this comment.
It would be better if you made hostname_ a variable in the host mock which defaults to "" and then set up an ON_CALL for it. Then your tests just need to change the value of hostname_ inside the mock both here and below. It's a little less error prone and more realistic. Your test below should actually setup a DNS host like this test, but because autoHostRewrite() returns false, it won't be swapped.
264d6f3 to
534898e
Compare
test/mocks/upstream/host.h
Outdated
| MOCK_CONST_METHOD0(stats, HostStats&()); | ||
| MOCK_CONST_METHOD0(zone, const std::string&()); | ||
|
|
||
| std::string hostname_{}; |
| MOCK_CONST_METHOD0(canary, bool()); | ||
| MOCK_CONST_METHOD0(cluster, const ClusterInfo&()); | ||
| MOCK_CONST_METHOD0(outlierDetector, Outlier::DetectorHostSink&()); | ||
| MOCK_CONST_METHOD0(hostname, const std::string&()); |
There was a problem hiding this comment.
add the ON_CALL to the constructor, and just ReturnRef hostname_
test/common/router/router_test.cc
Outdated
| HttpTestUtility::addDefaultHeaders(incoming_headers); | ||
| incoming_headers.Host()->value(req_host); | ||
|
|
||
| ON_CALL(*cm_.conn_pool_.host_, hostname()).WillByDefault(ReturnRef(dns_host)); |
There was a problem hiding this comment.
del this line, del dns_host, set host_.hostname_ = "scooby.doo"
test/common/router/router_test.cc
Outdated
| HttpTestUtility::addDefaultHeaders(outgoing_headers); | ||
| outgoing_headers.Host()->value(dns_host); | ||
|
|
||
| ON_CALL(*cm_.conn_pool_.host_, hostname()).WillByDefault(ReturnRef(dns_host)); |
There was a problem hiding this comment.
del this line, del dns_host, set host_.hostname_ = "scooby.doo"
Signed-off-by: Pengyuan Bian <bianpengyuan@google.com>
envoyproxy#504) * zh-translation: docs/root/configuration/http/http_filters/original_src_filter.rst * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com>
Enables envoy to rewrite Host headers for upstream requests, based on the hostname of the upstream instance (only for strict_dns and logical_dns clusters).
This is specifically useful when proxying to multiple cloud foundry instances (each of which has its own hostname, where the GoRouter routes requests to instances based on the hostname).
fixes #204
cc @mattklein123
While the changes are spread over a lot of files, they are pretty minor in 90% of the cases. The key changes are in the strict/logical dns implementations and hostdescription implementation.