Re: Use SNI with healthchecks

2018-04-26 Thread Willy Tarreau
On Fri, Apr 27, 2018 at 06:39:07AM +0200, Willy Tarreau wrote:
> I think that a few operators like strcmp() and concat() should be
> implemented to cover the short-term needs.

I forgot that I finally implemented concat() after talking about it for
about a year :-)  It is a good starting point to see how to implement
strcmp() if you're interested.

Willy



Re: Use SNI with healthchecks

2018-04-26 Thread Willy Tarreau
Hi Tim,

On Fri, Apr 27, 2018 at 12:16:15AM +0200, Tim Düsterhus wrote:
> The solution I got from "Holger Just" was:
> 
> > http-request   set-header X-CHECKSNI %[req.hdr(host)]==%[ssl_fc_sni] if 
> > { ssl_fc_has_sni }
> > http-request   deny  if { ssl_fc_has_sni } ! { 
> > hdr(X-CHECKSNI) -m reg -i ^(?.+)==\1$ }
> > http-request   del-header X-CHECKSNI
> 
> which works well, but is not intuitive and requires PCRE.
> 
> I have contemplated to add a patch with a `ssl_sni_http_host_mismatch`
> fetch, but I wasn't quite sure where to place it (it requires both http
> and ssl and thus is misplaced in both) and what parameters to pass
> (meaning SMP_USE_HRQHV et al). And thus I gave up.

I'd proceed differently I think. Just like we do have arithmetic operators
support variables as arguments, we could have string operators like strcmp()
which would support a variable as well. Then you could simply put your SNI
into a variable, and compare the host field with this variable.

In practice I've long wanted to have a stack-based sample expression
evaluation but while many of us think it will eventually appear, I think
that a few operators like strcmp() and concat() should be implemented to
cover the short-term needs.

> Not having this validation opens up possible security issues (validation
> of client certificates is based on SNI, routing is possibly based on the
> Host header).

For this specific case I agree.

> Personally I require SNI for everything and select the
> backends based on SNI and not the Host header.

This is dangerous because it's not what the backend servers will do,
so you need to keep this in mind to ensure you never switch to the
wrong place. Also as Lukas explained, when some certs overlap, you'll
only have the SNI matching the first Host. Apparently in your case it's
not an issue since you exactly compare them. Normally the reliable way
of doing it would be to ensure that SNI is valid (eg when you have to
check a client cert) but still rely on Host for routing.

> If you could give me some pointers on where to put such a fetch and what
> parameters to set I'd appreciate it. Or tell me that such a fetch is
> stupid, because it mixes information from different layers.

It's not stupid, it's just that I'm pretty sure that immediately after
being committed, someone will want to adjust its behaviour (ignore case,
stop on colon, etc). For this strcmp() will allow you to normalize each
party and then to compare the results.

Regards,
Willy



Re: Use SNI with healthchecks

2018-04-26 Thread Willy Tarreau
Hi Lukas,

On Fri, Apr 27, 2018 at 01:56:42AM +0200, Lukas Tribus wrote:
> Hello Willy,
> 
> 
> On 25 April 2018 at 12:16, Willy Tarreau  wrote:
> >> I'm not even sure that differentiate "Host" header from SNI values is
> >> possible on softwares like Nginx or Apache.
> >
> > It should not, that would be a violation of HTTP over TLS.
> 
> I think I disagree.
> 
> 
> This is very possible and in fact happens everyday. When the
> certificate has SAN's for www.example.org and mail.example.org, a
> browser uses a single TLS connection to access both domains - SNI will
> be whatever HTTP request warranted the TLS session in the first place
> (as SNI is only send in the TLS handshake's client_hello).

You're absolutely right.

> This only breaks when people try to content switch HTTP transactions
> that should be based on the Host header and look at the SNI header
> instead (which I'd argue is a layering violation). SNI should imho
> only be used for certificate selection at the TLS server
> endpoint/layer and best not be carried to upper layers.

Totally agreed, and I remember that both of us have been warning certain
people against the risks of using SNI for L7 switching.

> This is not limited to H2, I believe browsers do it in HTTP/1.1 as
> well, but here's the H2 RFC documenting this behavior [1]. H2 also
> introduces a new error code for servers unable to handle this, which
> is 421 [2]. Yes, at the end of RFC6066 section 3 [3] there is a SHOULD
> NOT about this. But it doesn't specifically address the HTTP use-case
> and it's not a MUST NOT. It doesn't make sense for a browser to throw
> away an already validated TLS sessions for which the hostname matches
> a SAN from the validated certificate.

I remember following a conversation on this exact subject on the HTTP WG,
though I didn't catch all the details. But it's true that in general
browsers will try hard to reuse existing connections as long as possible.

> Let's not make the FTP mess again and pull lower layer transport (or
> transport encryption) variables up into the application layer. Let the
> TLS server endpoint pick the certificate based on SNI and then stop
> looking at it would be my general advice.

Please note that we were discussing about the other way around, how to
automatically set SNI based on the Host header field, which is what
browsers and proxies normally do. However, this discussion made me
think about a case where we do not want to do this : if a browser
connects to a proxy using TLS (to protect user authentication), the
advertised SNI should not be the one from the Host header field but
the one matching the proxy host name, which doesn't appear in the
request and cannot be deduced. This is a good example showing that
we can't have SNI always deduced from the request.

> When TCP proxying TLS traffic and content switching based on SNI, one
> needs to make sure that the certificates do not overlap because of
> this connection reuse (just to provide another perspective), see [4]
> and [5].

Agreed. In my opinion, SNI-based switching is only usable when you know
that the certificates do not overlap. But in practice that's often the
case initially, until someone renews the certs with multiple SANs for
some purpose and starts to break everything.

Cheers,
Willy



Re: Use SNI with healthchecks

2018-04-26 Thread Lukas Tribus
Hello Willy,


On 25 April 2018 at 12:16, Willy Tarreau  wrote:
>> I'm not even sure that differentiate "Host" header from SNI values is
>> possible on softwares like Nginx or Apache.
>
> It should not, that would be a violation of HTTP over TLS.

I think I disagree.


This is very possible and in fact happens everyday. When the
certificate has SAN's for www.example.org and mail.example.org, a
browser uses a single TLS connection to access both domains - SNI will
be whatever HTTP request warranted the TLS session in the first place
(as SNI is only send in the TLS handshake's client_hello).

This only breaks when people try to content switch HTTP transactions
that should be based on the Host header and look at the SNI header
instead (which I'd argue is a layering violation). SNI should imho
only be used for certificate selection at the TLS server
endpoint/layer and best not be carried to upper layers.



This is not limited to H2, I believe browsers do it in HTTP/1.1 as
well, but here's the H2 RFC documenting this behavior [1]. H2 also
introduces a new error code for servers unable to handle this, which
is 421 [2]. Yes, at the end of RFC6066 section 3 [3] there is a SHOULD
NOT about this. But it doesn't specifically address the HTTP use-case
and it's not a MUST NOT. It doesn't make sense for a browser to throw
away an already validated TLS sessions for which the hostname matches
a SAN from the validated certificate.


Let's not make the FTP mess again and pull lower layer transport (or
transport encryption) variables up into the application layer. Let the
TLS server endpoint pick the certificate based on SNI and then stop
looking at it would be my general advice.


When TCP proxying TLS traffic and content switching based on SNI, one
needs to make sure that the certificates do not overlap because of
this connection reuse (just to provide another perspective), see [4]
and [5].



cheers,
lukas


[1] https://tools.ietf.org/html/rfc7540#section-9.1.1
[2] https://tools.ietf.org/html/rfc7540#section-9.1.2
[3] https://tools.ietf.org/html/rfc6066#section-3
[4] 
https://discourse.haproxy.org/t/sni-routing-to-servers-only-ever-sent-to-first-server/1265/4
[5] https://discourse.haproxy.org/t/h2-problem-with-multiple-backends/1650



Re: Use SNI with healthchecks

2018-04-26 Thread Tim Düsterhus
Willy,

Am 25.04.2018 um 12:16 schrieb Willy Tarreau:
> On Wed, Apr 25, 2018 at 09:48:13AM +, GALLISSOT VINCENT wrote:
>> I don't see a case were one would define a different check-sni or sni values
>> from the "Host" header.
> 
> It definitely must match in HTTP. *snip*
> 
>> I'm not even sure that differentiate "Host" header from SNI values is
>> possible on softwares like Nginx or Apache.
> 
> It should not, that would be a violation of HTTP over TLS.
> 

Unfortunately it’s not exactly easy to detect this condition using
haproxy. I asked on May 7th, 2017 on the list (thread: Compare against
variable string in ACL, Message-ID:
,
https://www.mail-archive.com/haproxy@formilux.org/msg26014.html).

The solution I got from "Holger Just" was:

>   http-request   set-header X-CHECKSNI %[req.hdr(host)]==%[ssl_fc_sni] if 
> { ssl_fc_has_sni }
>   http-request   deny  if { ssl_fc_has_sni } ! { 
> hdr(X-CHECKSNI) -m reg -i ^(?.+)==\1$ }
>   http-request   del-header X-CHECKSNI

which works well, but is not intuitive and requires PCRE.

I have contemplated to add a patch with a `ssl_sni_http_host_mismatch`
fetch, but I wasn't quite sure where to place it (it requires both http
and ssl and thus is misplaced in both) and what parameters to pass
(meaning SMP_USE_HRQHV et al). And thus I gave up.

Not having this validation opens up possible security issues (validation
of client certificates is based on SNI, routing is possibly based on the
Host header). Personally I require SNI for everything and select the
backends based on SNI and not the Host header.

If you could give me some pointers on where to put such a fetch and what
parameters to set I'd appreciate it. Or tell me that such a fetch is
stupid, because it mixes information from different layers.

Best regards
Tim Düsterhus



RE: Use SNI with healthchecks

2018-04-25 Thread GALLISSOT VINCENT

> It definitely must match in HTTP. However there's nothing making it mandatory
> to send HTTP checks, let alone a Host header field (eg: if sending a simple
> HTTP/1.0 request). However I'm noting the comment, because once we're able
> to more easily configure the HTTP checks, we could imagine that we'd always
> use SNI when "sni" is configured on the server line and an http check is in
> use.

That would be awesome !

> > I'm not even sure that differentiate "Host" header from SNI values is
> > possible on softwares like Nginx or Apache.

> It should not, that would be a violation of HTTP over TLS.

> > We should always use SNI & check-sni as the same value as the "Host" header
> > value,

> Yes, when we have one :-)

> > which in many cases should be the same value as the FQDN from the server 
> > line.

> This is where it's not always the case. Very commonly you'll have the
> individual server name (server1, server2, etc) and you need the application
> Host header.

Yes indeed, that's the point. We use HAProxy mainly to proxy traffic from
devices that don't like url/domain changes (like ISP boxes) to CDNs providers
so we rewrite a lot of things at HAProxy side (including Host).
I totally understand that most HAProxy users need it to forward traffic as it is
and therefore to keep SNI and other values from front clients requests.

> > I also think SNI should be defaulted when using ssl over server backend.

> We could possibly consider making it a default in a future version, indeed,
> but only once we have the ability to automatically retrieve correct values.

Would definitely be awesome!

> > Check-sni should default to the same value as sni but re-writable.

> Except that SNI comes from forwarded traffic and there's no forwarded traffic
> with the checks to extract the information from.

> > CDN providers like CloudFront or Akamai are using more and more SNI
> > by blowing up prices on non-sni configurations (CloudFront bills
> > 600$/month/vhost to avoid SNI)

> I can easily understand why they're doing this. IP addresses are becoming
> rare and it's a shame that some sites continue to waste them. With the
> rapid growth of SSL over the last few years, I can easily imagine that
> many sites have started to request their own IP addresses for no really
> valid reason (I believe that MSIE6 was the last browser not to support SNI
> but I could be wrong).

Absolutely, what for use of default sni also in haproxy would be royal ;)

Vincent

> Willy


Re: Use SNI with healthchecks

2018-04-25 Thread Willy Tarreau
On Wed, Apr 25, 2018 at 09:48:13AM +, GALLISSOT VINCENT wrote:
> I don't see a case were one would define a different check-sni or sni values
> from the "Host" header.

It definitely must match in HTTP. However there's nothing making it mandatory
to send HTTP checks, let alone a Host header field (eg: if sending a simple
HTTP/1.0 request). However I'm noting the comment, because once we're able
to more easily configure the HTTP checks, we could imagine that we'd always
use SNI when "sni" is configured on the server line and an http check is in
use.

> I'm not even sure that differentiate "Host" header from SNI values is
> possible on softwares like Nginx or Apache.

It should not, that would be a violation of HTTP over TLS.

> We should always use SNI & check-sni as the same value as the "Host" header
> value,

Yes, when we have one :-)

> which in many cases should be the same value as the FQDN from the server line.

This is where it's not always the case. Very commonly you'll have the
individual server name (server1, server2, etc) and you need the application
Host header.

> I also think SNI should be defaulted when using ssl over server backend.

We could possibly consider making it a default in a future version, indeed,
but only once we have the ability to automatically retrieve correct values.

> Check-sni should default to the same value as sni but re-writable.

Except that SNI comes from forwarded traffic and there's no forwarded traffic
with the checks to extract the information from.

> CDN providers like CloudFront or Akamai are using more and more SNI
> by blowing up prices on non-sni configurations (CloudFront bills
> 600$/month/vhost to avoid SNI)

I can easily understand why they're doing this. IP addresses are becoming
rare and it's a shame that some sites continue to waste them. With the
rapid growth of SSL over the last few years, I can easily imagine that
many sites have started to request their own IP addresses for no really
valid reason (I believe that MSIE6 was the last browser not to support SNI
but I could be wrong).

Willy



RE: Use SNI with healthchecks

2018-04-25 Thread GALLISSOT VINCENT
I'll test the "setenv" approach soon.


I don't see a case were one would define a different check-sni or sni values 
from the "Host" header.

I'm not even sure that differentiate "Host" header from SNI values is possible 
on softwares like Nginx or Apache.


We should always use SNI & check-sni as the same value as the "Host" header 
value,

which in many cases should be the same value as the FQDN from the server line.

I also think SNI should be defaulted when using ssl over server backend.

Check-sni should default to the same value as sni but re-writable.

CDN providers like CloudFront or Akamai are using more and more SNI
by blowing up prices on non-sni configurations (CloudFront bills 
600$/month/vhost to avoid SNI)

Vincent


De : Willy Tarreau 
Envoyé : mercredi 25 avril 2018 09:16
À : Jonathan Matthews
Cc : GALLISSOT VINCENT; Lukas Tribus; haproxy@formilux.org
Objet : Re: Use SNI with healthchecks

On Tue, Apr 24, 2018 at 06:50:13PM +, Jonathan Matthews wrote:
> [Top post; fight me]

Grrr

> You could either read an environment variable inherited from outside the
> process, or use "setenv" or "presetenv" as appropriate to DRY your config
> out.
>
> The fine manual describes how you would refer to this envvar in section
> 2.3, regardless of which of those options you use to set it.

That's indeed a possibility. In Vincent's case I'm seeing that he uses the
same name as the FQDN one. That makes me think we could possibly have a
special check-sni value to use the FQDN from the server line. That would
have the benefit of making it easier to place in a default-server statement.
I just don't know how often it happens that the SNI used for checks has to
match the FQDN declared in the configuration.

Willy


Re: Use SNI with healthchecks

2018-04-25 Thread Willy Tarreau
On Tue, Apr 24, 2018 at 06:50:13PM +, Jonathan Matthews wrote:
> [Top post; fight me]

Grrr

> You could either read an environment variable inherited from outside the
> process, or use "setenv" or "presetenv" as appropriate to DRY your config
> out.
> 
> The fine manual describes how you would refer to this envvar in section
> 2.3, regardless of which of those options you use to set it.

That's indeed a possibility. In Vincent's case I'm seeing that he uses the
same name as the FQDN one. That makes me think we could possibly have a
special check-sni value to use the FQDN from the server line. That would
have the benefit of making it easier to place in a default-server statement.
I just don't know how often it happens that the SNI used for checks has to
match the FQDN declared in the configuration.

Willy



Re: Use SNI with healthchecks

2018-04-24 Thread Jonathan Matthews
[Top post; fight me]

You could either read an environment variable inherited from outside the
process, or use "setenv" or "presetenv" as appropriate to DRY your config
out.

The fine manual describes how you would refer to this envvar in section
2.3, regardless of which of those options you use to set it.

J

On Tue, 24 Apr 2018 at 16:45, GALLISSOT VINCENT 
wrote:

> I migrated to 1.8 and sni + check-sni *are working fine* with the
> following code:
>
>
>
> 88
>
> backend cloudfront
> http-request set-header Host 123456789abcde.cloudfront.net
> option httpchk HEAD /check HTTP/1.1\r\nHost:\
> 123456789abcde.cloudfront.net
> server applaunch 123456789abcde.cloudfront.net:443 check resolvers
> mydns  no-sslv3 ssl verify required ca-file ca-certificates.crt sni 
> req.hdr(host)
> check-sni 123456789abcde.cloudfront.net
>
> 88
>
>
> Obviously I cannot use %[req.hdr(host)] for "option httpchk" nor for
> "check-sni" directives.
>
>
> Do you know how can I define only one time my Host header in the code
> above ?
>
>
> Thanks,
>
> Vincent
>
>
> ------
> *De :* GALLISSOT VINCENT
> *Envoyé :* lundi 23 avril 2018 17:33
> *À :* Lukas Tribus
> *Cc :* haproxy@formilux.org
> *Objet :* RE: Use SNI with healthchecks
>
>
> Thank you very much for your answers,
>
> I'll migrate to 1.8 asap to fix this.
>
>
> Vincent
>
>
>
> ----------
> *De :* lu...@ltri.eu  de la part de Lukas Tribus <
> lu...@ltri.eu>
> *Envoyé :* lundi 23 avril 2018 17:18
> *À :* GALLISSOT VINCENT
> *Cc :* haproxy@formilux.org
> *Objet :* Re: Use SNI with healthchecks
>
> Hello Vincent,
>
>
> On 23 April 2018 at 16:38, GALLISSOT VINCENT 
> wrote:
> > Does anybody know how can I use healthchecks over HTTPS with SNI support
> ?
>
> You need haproxy 1.8 for this, it contains the check-sni directive
> which allows to set SNI to a specific string for the health check:
>
> http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-check-sni
>
>
>
>
> Regards,
>
> Lukas
>
-- 
Jonathan Matthews
London, UK
http://www.jpluscplusm.com/contact.html


RE: Use SNI with healthchecks

2018-04-24 Thread GALLISSOT VINCENT
I migrated to 1.8 and sni + check-sni are working fine with the following code:


88

backend cloudfront
http-request set-header Host 123456789abcde.cloudfront.net
option httpchk HEAD /check HTTP/1.1\r\nHost:\ 123456789abcde.cloudfront.net
server applaunch 123456789abcde.cloudfront.net:443 check resolvers mydns  
no-sslv3 ssl verify required ca-file ca-certificates.crt sni req.hdr(host) 
check-sni 123456789abcde.cloudfront.net
88


Obviously I cannot use %[req.hdr(host)] for "option httpchk" nor for 
"check-sni" directives.


Do you know how can I define only one time my Host header in the code above ?


Thanks,

Vincent



De : GALLISSOT VINCENT
Envoyé : lundi 23 avril 2018 17:33
À : Lukas Tribus
Cc : haproxy@formilux.org
Objet : RE: Use SNI with healthchecks


Thank you very much for your answers,

I'll migrate to 1.8 asap to fix this.


Vincent



De : lu...@ltri.eu  de la part de Lukas Tribus 
Envoyé : lundi 23 avril 2018 17:18
À : GALLISSOT VINCENT
Cc : haproxy@formilux.org
Objet : Re: Use SNI with healthchecks

Hello Vincent,


On 23 April 2018 at 16:38, GALLISSOT VINCENT  wrote:
> Does anybody know how can I use healthchecks over HTTPS with SNI support ?

You need haproxy 1.8 for this, it contains the check-sni directive
which allows to set SNI to a specific string for the health check:

http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-check-sni




Regards,

Lukas


RE: Use SNI with healthchecks

2018-04-23 Thread GALLISSOT VINCENT
Thank you very much for your answers,

I'll migrate to 1.8 asap to fix this.


Vincent



De : lu...@ltri.eu  de la part de Lukas Tribus 
Envoyé : lundi 23 avril 2018 17:18
À : GALLISSOT VINCENT
Cc : haproxy@formilux.org
Objet : Re: Use SNI with healthchecks

Hello Vincent,


On 23 April 2018 at 16:38, GALLISSOT VINCENT  wrote:
> Does anybody know how can I use healthchecks over HTTPS with SNI support ?

You need haproxy 1.8 for this, it contains the check-sni directive
which allows to set SNI to a specific string for the health check:

http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-check-sni




Regards,

Lukas


Re: Use SNI with healthchecks

2018-04-23 Thread Lukas Tribus
Hello Vincent,


On 23 April 2018 at 16:38, GALLISSOT VINCENT  wrote:
> Does anybody know how can I use healthchecks over HTTPS with SNI support ?

You need haproxy 1.8 for this, it contains the check-sni directive
which allows to set SNI to a specific string for the health check:

http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-check-sni




Regards,

Lukas



Re: Use SNI with healthchecks

2018-04-23 Thread Jerome Magnin
Hi Vincent,

On Mon, Apr 23, 2018 at 02:38:32PM +, GALLISSOT VINCENT wrote:
> Hi all,
> 
> 
> I want to use SNI with httpchk on HAProxy 1.7.10 to connect to  CloudFront 
> distributions as backend servers.
> 
> I saw in this mailing-list archives that SNI is not used by default even when 
> using the ssl directive.
> 
> We don't pay for SNI on that distribution, that means CloudFront doesn't 
> provide a certificate on its default vhost.
> 
> Because of that, all healthchecks fail with "handshake failure".
> 
> 
> I temporarily by-passed the issue by adding "port 80" to allow healthchecks 
> over HTTP:
> 
> 
> option httpchk HEAD /check HTTP/1.1\r\nHost:\ 
> mydistribution.cloudfront.net
> server mydistribution mydistribution.cloudfront.net:443 check resolvers 
> mydns port 80 cookie no-sslv3 ssl verify required ca-file ca-certificates.crt
> 
> 
> Does anybody know how can I use healthchecks over HTTPS with SNI support ?
>

Prior to 1.8 if you want SNI in the health checks you have to use something
along these lines:

backend moo
mode http
option httpchk GET / HTTP/1.0
server s1 my.example.host:443 check addr 127.0.0.1 port 1234 ssl sni 
str("my.example.host") 


listen foo
bind 127.0.0.1:1234
server s1 my.example.host:443 sni str("my.example.host") ssl

That's because sni keyword only applies to proxied traffic, and not checks, so
you check through a listener that will add the sni.

With 1.8 and later, you just use check-sni  on server lines.

cheers,
Jérôme 



Use SNI with healthchecks

2018-04-23 Thread GALLISSOT VINCENT
Hi all,


I want to use SNI with httpchk on HAProxy 1.7.10 to connect to  CloudFront 
distributions as backend servers.

I saw in this mailing-list archives that SNI is not used by default even when 
using the ssl directive.

We don't pay for SNI on that distribution, that means CloudFront doesn't 
provide a certificate on its default vhost.

Because of that, all healthchecks fail with "handshake failure".


I temporarily by-passed the issue by adding "port 80" to allow healthchecks 
over HTTP:


option httpchk HEAD /check HTTP/1.1\r\nHost:\ mydistribution.cloudfront.net
server mydistribution mydistribution.cloudfront.net:443 check resolvers 
mydns port 80 cookie no-sslv3 ssl verify required ca-file ca-certificates.crt


Does anybody know how can I use healthchecks over HTTPS with SNI support ?


Many thanks,

Vincent