-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Auto host rewrite option for strict_dns and logical_dns clusters #504
Conversation
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.
overall nice work, a few comments.
@@ -97,6 +98,15 @@ host_rewrite | |||
*(optional, string)* Indicates that during forwarding, the host header will be swapped with this | |||
value. | |||
|
|||
.. _config_http_conn_man_route_table_route_auto_host_rewrite: |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -198,6 +198,11 @@ class RouteEntry { | |||
* @return const VirtualHost& the virtual host that owns the route. | |||
*/ | |||
virtual const VirtualHost& virtualHost() const PURE; | |||
|
|||
/** | |||
* @return bool true if the Host header should be overwritten with the Upstream hostname. |
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.
"Host/:authority header"
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.
s/Upstream/upstream
@@ -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_); |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, we just use host-rewrite (in ingress) and SDS.
@@ -21,8 +21,7 @@ LogicalDnsCluster::LogicalDnsCluster(const Json::Object& config, Runtime::Loader | |||
} | |||
|
|||
dns_url_ = hosts_json[0]->getString("url"); | |||
Network::Utility::hostFromTcpUrl(dns_url_); |
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.
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
HttpTestUtility::addDefaultHeaders(headers); | ||
headers.Host()->value(req_host); | ||
router_.decodeHeaders(headers, true); | ||
EXPECT_EQ(req_host, headers.Host()->value().c_str()); |
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.
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
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.
2 minor things otherwise looks good.
@@ -22,7 +22,9 @@ request. The router filter supports the following features: | |||
level. | |||
* :ref:`Path <config_http_conn_man_route_table_route_path_redirect>`/:ref:`host | |||
<config_http_conn_man_route_table_route_host_redirect>` redirection at the route level. | |||
* :ref:`Host rewriting <config_http_conn_man_route_table_route_host_rewrite>`. | |||
* :ref:`Explicit host rewriting <config_http_conn_man_route_table_route_host_rewrite>`. | |||
* :ref:`Automatic host rewriting <config_http_conn_man_route_table_route_auto_host_rewrite>` based on DNS name of |
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.
nit: "... the DNS name ..."
test/common/router/router_test.cc
Outdated
.WillOnce(Invoke([&](const Upstream::HostDescriptionPtr host) | ||
-> void { EXPECT_EQ(host_address_, host->address()); })); | ||
EXPECT_CALL(callbacks_.route_->route_entry_, autoHostRewrite()).WillOnce(Return(true)); | ||
EXPECT_CALL(*cm_.conn_pool_.host_, hostname()).WillRepeatedly(ReturnRef(dns_host)); |
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.
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(address, Network::Address::InstancePtr()); | ||
MOCK_CONST_METHOD0(stats, HostStats&()); | ||
MOCK_CONST_METHOD0(zone, const std::string&()); | ||
|
||
std::string hostname_{}; |
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.
{} not needed
@@ -56,10 +56,12 @@ class MockHostDescription : public HostDescription { | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
del this line, del dns_host, set host_.hostname_ = "scooby.doo"
Signed-off-by: Pengyuan Bian <[email protected]>
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 <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> * Update docs/root/configuration/http/http_filters/original_src_filter.rst Co-authored-by: majinghe <[email protected]> Co-authored-by: majinghe <[email protected]>
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.