On Tue, Oct 22, 2019, 10:27 PM Morotti, Romain D < romain.d.moro...@jpmorgan.com> wrote:
> Hello, > > > > The use case is to load balance applications in multiple datacenters or > regions. > > The common pattern today to cover multiple locations is to deploy services > in each location separately and independently. > > > > This happens with kubernetes for example, where a cluster is typically > limited to a datacenter. Covering multiple locations is done by having > independent clusters and provisioning the application to each of them. > > e.g. myapp.kube-naest1.example.com + myapp.kube-euwest.example.com. > > > > As a developer, I want to present the application on a single consistent > URL with failover, e.g. myapp.example.com. > > Without getting into too much details, this is done with a layer of load > balancing and this requires careful consideration around DNS, Host header, > TLS SNI, certificates and healthcheck to work end-to-end. > > > > Let's take the two most basic use cases. > > > > # multi clusters use case > > backend foo > > mode http > > option httpchk GET /healthcheck > > http-send-name-header Host > > server myapp.kube-naest1.example.com myapp.kube-naest1.example.com:80 > > server myapp.kube-naest2.example.com myapp.kube-naest2.example.com:80 > > > > # multi regions use case > > backend foo > > mode http > > option httpchk GET /healthcheck > > http-send-name-header Host > > server myapp.kube-naest1.example.com myapp.kube-naest1.example.com:80 > > server myapp.kube-euwest.example.com myapp.kube-euwest.example.com:80 > > > > Each backend expects its own Host header, otherwise kubernetes cannot > route and serve the request. > Can't you just set an Alias on your backend with all the expected domains to serve for that vhost? > In haproxy, this can be made to work using the "http-send-name-header > Host" directive, that overrides the Host header per backend. > > > > This setup fails in practice because of the healthcheck failing. The > healthcheck request sent by haproxy doesn't have a host header. It ignores > the "http-send-name-header" directive and there is no option to set the > healthcheck host per backend. > > (Similar challenge with TLS SNI, that is easily worked around by disabling > TLS checks. There are settings "sni req.hdr(host)" and "check-sni" to > adjust, with little information on all these settings combine). > > > > The proposed patch intended to add one setting per backend to manage the > host header end-to-end consistently and reliably: adjusting healthchecks, > forwarding requests and TLS domain. > > > > If you prefer not to do this, I can think of a less intrusive patch to > configure the healthcheck. > > Since there is already the "http-send-name-header Host" directive, whose > main use case is to adjust the Host header per backend. > > I could patch the healthcheck code to follow that directive when running > https healthchecks, if that’s okay with you. > > > > Thinking of it, it could be considered a bug that the healthcheck doesn't > do that already. If I configure all my servers to get a header, it’s > certainly important and I expect the healthcheck to get it too. > > > > Related questions and issues: > > > https://serverfault.com/questions/876871/configure-haproxy-to-include-host-headers-for-different-backends > > > https://serverfault.com/questions/770737/making-haproxy-pass-a-host-name-in-httpcheck > > > https://serverfault.com/questions/594669/haproxy-health-checking-multiple-servers-with-different-host-names > > > > > > Regards. > > > > > > *From:* Willy Tarreau [mailto:w...@1wt.eu] > *Sent:* 03 October 2019 05:51 > *To:* Morotti, Romain D (CIB Tech, GBR) <romain.d.moro...@jpmorgan.com> > *Cc:* haproxy@formilux.org; Sayar, Guy H (CIB Tech, GBR) < > guy.h.sa...@jpmorgan.com> > *Subject:* Re: [PR/FEATURE] support for virtual hosts / Host header per > server > > > > Hello Romain, > > On Tue, Oct 01, 2019 at 12:08:03PM +0000, Morotti, Romain D wrote: > > What is the status on this? > > Sorry, but it took some time to work on other priorities, and to be > honest, the subject looked scary enough to deserve enough time to > study it. Sadly, if I can say, the subject was pretty descriptive of > what it does, and this is fundamentally wrong. > > So just to summarize for those who haven't had a look at the patch, > what this patch does is to replace the host header in requests sent to > a server with one specified for this server, resulting in each server > within the same farm to run on a different vhost. This goes back to > the errors that plagued many hosting infrastructures in the late 90s > and early 2000s where redirects, hosts in pages etc were wrong because > the application was called with an internal name instead of the correct > one. Moreover this used to prevent servers from being shared between > multiple hosts since the host header was containing rubish. For > reference, Apache merged the ProxyPreserveHost in 2.0.31 in 2002 to put > an end to that madness. But here you're escalating this to a new level > and involving it in load balancing, 15 years after everyone managed to > fix that early mistake and bury it deeply forever. So in short for a > request sent to foo.bar.com, you'll randomly forward it as being for > foo1.bar.com, bar.foo2.com, www.example.org etc... all in the same farm! > It's as if when launching my browser on Amazon I was presented eBay, > Amazon and Aliexpress in a round robin fashion. I'm exagerating but it > really is the same principle. > > It is critically important that Host headers are not tampered with > anymore, especially in a load balanced setup where all nodes must > absolutely receive the exact same requests. Nowadays they're used > way more than in the early 2000, you have them in Set-Cookie, > Access-Control-Allow-Origin header with CORS, Location for redirects > (obviously), logs, statistics. It makes absolutely no sense to deploy > multiple servers in a same farm on different host names for the same > service. And no, migrating from an old Apache 1.3 config relying on > ProxyPass is not a valid excuse in 2019 for reintroducing such > architectural flaws! > > Such mistakes are still occasionally encountered in field, but extremely > rarely. Usually it's after their author, and single defender, quits the > company and their substitute discovers the mess and says "Houston, we > have a problem". But fortunately while I've met it very few times with > reverse proxies over the last decade, I never met it at all within a > load balancing farm in 18 years! > > I'm seeing this as the outcome of someone having shoot himself in the > foot, then aiming at the knee in order not to feel the foot's pain > anymore. But here I don't want to engage every users' knee in front > of this gun. > > For the part concerning the health checks however your point is totally > valid and I absolutely hate the "\r\nHost:foo" hack that we're relying on > from time to time. I'd like to see checks reworked so that we can pass > various headers etc. I'm not fond of having just a vhost directive to be > used by checks because 1) it's confusing and 2) we're just hiding the dust > under the carpet. We do need really improved checks and dealing with Host > only is not sufficient. Some users need to pass cookies, auth headers, > user-agent, or x-forwarded-for headers for example, and such configs are > really really dirty. Usually they switch to tcp-checks but then they cannot > use fancy features like disable-on-404. > > > > The lack of this functionality is a blocker to use HAProxy with kubernetes. > > I'd say that many existing haproxy users in kubernetes would probably > disagree with this bold claim. Saying that you're facing difficulties > and are seeking for configuration help would possibly be more accurate. > > In my opinion at this point it's preferable that you clearly describe > the problem you're facing so that it can be split in 3 parts : > > - architecture issues > - configuration issues > - haproxy limitations > > I really suspect that you're facing a bit of each, and that for example > you're having an issue with your checks being unusable or unreliable on > the *real* application, forcing you to check a dummy one running on the > server itself, which does expect to be called with its own name and that > since haproxy uses the same check requests for all hosts you're facing > difficulties running the dummy checks. But maybe fixing the application > so that it can really be checked would be the best solution, maybe > configuring the dummy check application with a proper host would be the > second best solution, maybe using HTTP/1.0 checks to get rid of Host > (as many people do notably on static servers to end up on the default > vhost) would work fine, or maybe we need to perform minimal changes to > the checks to deal with a specific case. > > Among the things I've been thinking about in the past regarding short > term improvements to the checks that could remain compatible with a > whole rewrite, I'd enumerate : > - a new directive "http-check send-cookie" to bring the ability to > automatically send the cookie header with the server's value when > configured ; some would probably suggest that it should always be > set and does not even require an option maybe. > > - the ability to define a general purpose argument on a server line > ("check-arg") that would be sent in any header after the checks, > and as a side effect could be used to send a Host header. > > For example we could have this : > > backend foo > # send "X-Farm-Name: foo" in all checks > server foo1 1.1.1.1:8000 check-arg foo > server foo2 1.1.1.2:8000 check-arg foo > http-check send-arg X-Farm-Name > > As well as this : > > backend foo > # send "X-Server-Name: foo1/2" in all checks > server foo1 1.1.1.1:8000 check-arg foo1 > server foo2 1.1.1.2:8000 check-arg foo2 > http-check send-arg X-Server-Name > > Or this : > > backend foo > # send "Host: foo1/2.example.internal" in all checks > server foo1 1.1.1.1:8000 check-arg foo1.example.internal > server foo2 1.1.1.2:8000 check-arg foo2.example.internal > http-check send-arg Host > > We could even be more forward-thinking and allow to define and reference > multiple such arguments : > > backend foo > # send "Host: foo1/2.example.internal" in all checks > server foo1 1.1.1.1:8000 check-arg(foo,foo1.example.internal) > server foo2 1.1.1.2:8000 check-arg(foo,foo2.example.internal) > http-check send-arg(1) X-Farm-Name > http-check send-arg(2) Host > > These are just ideas of course and code speaks better. > > If you think that your issue really is only related to health checks > (which would then be quite a relief) and that something like above would > suit your needs, I'm willing to help you get this merged before the code > freeze. I just don't want to spend extra energy for nothing :-/ > > Ideas and suggestions are welcome. > > Thanks, > Willy > > This message is confidential and subject to terms at: > https://www.jpmorgan.com/emaildisclaimer including on confidential, > privileged or legal entity information, viruses and monitoring of > electronic messages. If you are not the intended recipient, please delete > this message and notify the sender immediately. Any unauthorized use is > strictly prohibited. >