fabiolb / fabio

Consul Load-Balancing made simple
https://fabiolb.net
MIT License
7.27k stars 616 forks source link

Routing table order resolution seem broken #580

Open IxDay opened 5 years ago

IxDay commented 5 years ago

According to documentation routing order is taken from service name in alphabetical order. I push the following to consul:

curl --request PUT --data 'route add aaa vault.rulz.xyz:80/ https://vault.rulz.xyz/$path opts "redirect=301"' \
     http://consul.rulz.xyz/v1/kv/fabio/config/01_vault
curl --request PUT --data 'route add bbb vault.rulz.xyz/ https://172.17.0.1:8200 opts "tlsskipverify=true"' \
     http://consul.rulz.xyz/v1/kv/fabio/config/02_vault

When I check the route table from ui, services are in the wrong order, bbb comes before aaa, then when I run curl commands, https endpoint work, but http does not redirect me.

It seems that the order is based on the source string and not on service name. Am I doing something wrong?

I use version 1.5.10

magiconair commented 5 years ago

Hi @IxDay , If you are referring to https://fabiolb.net/cfg/#routing-rules then there is no such rule. Routing is solely based on hostname and path. The service name is only used for filtering. Can you point to where you've read that?

IxDay commented 5 years ago

I mostly inferred it from the screenshots as service-a is coming before service-b even if the hostnames are not alphabetically ordered. My main issue is to force a service to be https only, as, if the order is based on hostname only, the redirection will be in the form:

route add some.name:80/ https://some.name/$path opts "redirect=301"
route add some.name service.endpoint proto=https 

But some.name:80 will always come after some.name and thus making the redirection never happening.

aaronhurt commented 5 years ago

Are you terminating TLS on fabio or are you trying to pass HTTPS directly to the backend? Additionally, you can make your second route in the example more explicit by specifying port 443.

In our setup we have one redirect for the main domain that looks very close to yours ...

route add http-redirect foo.com:80 https://foo.com$path opts "redirect=301"

We have fabio listening on port 80 and 443 ...

proxy.addr = 1.2.3.4:80;proto=http;rt=60s;wt=60s,\
             1.2.3.4:443;proto=https;rt=60s;wt=60s;cs=all;tlsmin=10

In this setup anything that comes in on port 80 hits the redirect and thus arrives at the port 443 listener.

IxDay commented 5 years ago

Ok, I came with a proper one line example:

fabio -proxy.addr=":80,:443;proto=tcp+sni" -registry.backend=static -insecure -log.level TRACE -registry.static.routes='
route add foo rulz.xyz/ https://172.17.0.4:443/ opts "proto=https tlsskipverify=true"
route add bar rulz.xyz:80/ https://rulz.xyz/$path opts "redirect=301"'

Here I have a https service at 172.17.0.4, I use tcp+sni, when connecting to https endpoint I get the proper behavior:

curl -Lkvvv --resolve "rulz.xyz:80:172.17.0.3" --resolve "rulz.xyz:443:172.17.0.3" https://rulz.xyz

result:

* Added rulz.xyz:443:172.17.0.3 to DNS cache
* Hostname rulz.xyz was found in DNS cache
*   Trying 172.17.0.3...
* TCP_NODELAY set
* Connected to rulz.xyz (172.17.0.3) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=foo.com
*  start date: Dec 11 09:06:57 2018 GMT
*  expire date: Dec 11 09:06:57 2019 GMT
*  issuer: CN=foo.com
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET / HTTP/1.1
> Host: rulz.xyz
> User-Agent: curl/7.62.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200
< Content-Type: text/plain
<
Hello World!
* TLSv1.2 (IN), TLS alert, close notify (256):
* Closing connection 0
* TLSv1.2 (OUT), TLS alert, close notify (256):

However, If I try to use the http endpoint:

curl -Lkvvv --resolve "rulz.xyz:80:172.17.0.3" --resolve "rulz.xyz:443:172.17.0.3" http://rulz.xyz

result:

* Added rulz.xyz:80:172.17.0.3 to DNS cache
* Added rulz.xyz:443:172.17.0.3 to DNS cache
* Hostname rulz.xyz was found in DNS cache
*   Trying 172.17.0.3...
* TCP_NODELAY set
* Connected to rulz.xyz (172.17.0.3) port 80 (#0)
> GET / HTTP/1.1
> Host: rulz.xyz
> User-Agent: curl/7.62.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Tue, 11 Dec 2018 12:58:00 GMT
< Content-Length: 13
<
Hello World!
* Connection #0 to host rulz.xyz left intact

No redirection occurs, checking the routes in alphabetical order push rulz.xyz:80/ after the service declaration, and avoid the redirection, If I declare my routes this way:

fabio -proxy.addr=":80,:443;proto=tcp+sni" -registry.backend=static -insecure -log.level TRACE -registry.static.routes='
route add foo rulz.xyz:443/ https://172.17.0.4:443/ opts "proto=https tlsskipverify=true"
route add bar rulz.xyz:80/ https://rulz.xyz:443/$path opts "redirect=301"'

I get: 2018/12/11 13:00:03 [WARN] No route for rulz.xyz

eagle1981 commented 5 years ago

Same issue, same config, but return 502

< HTTP/1.1 502 Bad Gateway < Date: Fri, 22 Feb 2019 05:47:22 GMT < Content-Length: 0