traefik / traefik

The Cloud Native Application Proxy
https://traefik.io
MIT License
50.91k stars 5.07k forks source link

Print a warning if a router is configured with both HTTP and HTTPs entrypoints #10930

Closed sandnabba closed 2 months ago

sandnabba commented 2 months ago

Welcome!

What did you expect to see?

Hello!

I recently spent a few hours troubleshooting something that in the end was very simple.

As I'm new to Traefik, I just followed one of the many guides to set things up. In the beginning everything was straight-forward. After getting HTTP to work, I proceeded with HTTPs. My usual approach is to get connectivity to work first, and then fixing the actual certificate (and other tuning).

At a first look, it looks very simple: https://doc.traefik.io/traefik/routing/routers/

If not specified, HTTP routers will accept requests from all EntryPoints in the [list of default EntryPoints]

https://doc.traefik.io/traefik/https/overview/

Traefik supports HTTPS & TLS, which concerns roughly two parts of the configuration: routers, and the TLS connection (and its underlying certificates).

When a router has to handle HTTPS traffic, it should be specified with a tls field of the router definition.

So, I basically just proceeded adding a HTTPs entrypoint, that just as expected was added to my router: image

But in reality, the HTTPS traffic is just routed into nowhere, with no clear error message.

It's first when you dive deep into the documentation, reading the TLS part of the router docs that you find that a router can only use HTTP, or HTTPS.

Searching the community forum, I see a large amount of posts related to "HTTPs and 404" messages, so I'm not the first one to stumble upon this.

It would have helped me a lot to get at least some hint about this, and I think that there are many places where this could be checked, but I think these would be the most logical:

I think this would be a great usability improvement for new users.

rtribotte commented 2 months ago

Hello @sandnabba,

Thanks for your interest in Traefik!

We are aware that router TLS configuration and entryPoint TLS configuration are sometime confusing, and we would like to improve the documentation in that regard.

Nevertheless, we are unsure to follow every step you took, could please elaborate/be more specific, even by sharing static and dynamic configuration?

sandnabba commented 2 months ago

Hi, sure!

My static configuration (for the entrypoints):

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

The base for this configuration is the Routing & Loadbalancing -> Entrypoint documentation page: https://doc.traefik.io/traefik/routing/entrypoints/

An interesting note on this page is that it specifically states:

If there is no EntryPoint with the AsDefault option set to true, then the list of default EntryPoints includes all HTTP/TCP EntryPoints.

But it does not mention that this might result in "conflicting" configuration.

After setting up the above entrypoints, I proceeded to the "Routers" documentation: https://doc.traefik.io/traefik/routing/routers/#entrypoints Again, it's clearly stated that:

If not specified, HTTP routers will accept requests from all EntryPoints in the list of default EntryPoints.

So I basically just copy-pasted the "Listens to Every EntryPoint" example (from the page above) and combined it with the "A Service with One Server" service example from the service documentation: https://doc.traefik.io/traefik/routing/services/#servers

Result:

http:
  services:
    test-service:
      loadBalancer:
        servers:
        - url: "http://172.20.0.2:80"
  routers:
    test-router:
      rule: "Host(`test.mydomain`)"
      service: "test-service"

As expected, both entrypoints was connected to the "test-router" (this is when I made the screenshot of the dashboard in the original post). And here I expected that traffic entering the HTTP endpoint should be routed to the service over HTTP, and that HTTPs traffic should be routed over HTTPS, since the dashboard shows that both entrypoints are connected to the same router. (But in reality they are not).

So I think there are two parts to be done here. First of all the documentation should be updated. Maybe provide a dedicated HTTP to HTTPS example? (Since that is a very common usecase). By much googling, I went with the following solution (using the almost secret "noop@internal" endpoint).

# Static:
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
    asDefault: true
    http:
      tls: {}

# Dynamic:
http:
  middlewares:
    http_to_https:
      redirectScheme:
        scheme: https
        permanent: true
  routers:
    forwarder:
      rule: "HostRegexp(`host.+`)"
      entrypoints: "web"
      middlewares: "http_to_https"
      service: "noop@internal"

But I also think that Traefik should prevent me from using this "broken" configuration. According to the dashboard, it really looks like everything should work, when in reality it does not.

kevinpollet commented 2 months ago

And here I expected that traffic entering the HTTP endpoint should be routed to the service over HTTP, and that HTTPs traffic should be routed over HTTPS, since the dashboard shows that both entrypoints are connected to the same router. (But in reality they are not).

Could you elaborate on this? because we are not sure to understand everything, do you have any errors?

sandnabba commented 2 months ago

Could you elaborate on this? because we are not sure to understand everything, do you have any errors?

Yes, I'm getting a HTTP 404 trying HTTPS:

mil@emil-work: ~ $> curl -k -v -o /dev/null https://test.mydomain
* processing: https://test.mydomain
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 10.1.1.100:443...
* Connected to test.mydomain (10.1.1.100) port 443
* ALPN: offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [15 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [879 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [36 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [36 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=TRAEFIK DEFAULT CERT
*  start date: Jul 23 19:50:51 2024 GMT
*  expire date: Jul 23 19:50:51 2025 GMT
*  issuer: CN=TRAEFIK DEFAULT CERT
*  SSL certificate verify result: self-signed certificate (18), continuing anyway.
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [122 bytes data]
* using HTTP/2
* h2 [:method: GET]
* h2 [:scheme: https]
* h2 [:authority: test.mydomain]
* h2 [:path: /]
* h2 [user-agent: curl/8.2.1]
* h2 [accept: */*]
* Using Stream ID: 1
} [5 bytes data]
> GET / HTTP/2
> Host: test.mydomain
> User-Agent: curl/8.2.1
> Accept: */*
> 
{ [5 bytes data]
< HTTP/2 404

Http over port 80 works fine. But according to the dashboard, port 443 is routed to the service as well.

Another interesting note is the access log, where we can clearly see that HTTPS traffic ends up in "nowhere" (no service):

10.1.1.3 - - [23/Jul/2024:20:13:04 +0000] "GET / HTTP/2.0" 404 19 "-" "-" 1691 "-" "-" 0ms
10.1.1.3 - - [23/Jul/2024:20:13:07 +0000] "GET / HTTP/1.1" 200 266613 "-" "-" 1692 "test-router@file" "http://172.20.0.2:80" 442ms
rtribotte commented 2 months ago

Hello @sandnabba,

In the example you have shared:

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

The two entryPoints are just ports on which Traefik will listen.

In the second example configuration you have shared:

http:
  services:
    test-service:
      loadBalancer:
        servers:
        - url: "http://172.20.0.2:80"
  routers:
    test-router:
      rule: "Host(`test.mydomain`)"
      service: "test-service"

The router has no TLS configuration and is not attached to any entryPoint.

At this point, Traefik is (only) able to handle HTTP (non-TLS) traffic on both entryPoints (the port is not determining if the request should be TLS or not).

In the third example you have shared:

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
    asDefault: true
    http:
      tls: {}

This makes the router (that is not specifying the entryPoint to which it should be attached) to be attached to the websecure entryPoint, and inherit from it's http configuration, so becomes an HTTPS router.

It seems that your issue is related to a configuration issue and the GitHub issue tracker is dedicated to bug and feature requests.

For help on your configuration, please join our Community Forum and reach out to us on the Traefik v2 section.

We will close this issue accordingly but feel free to re-open it if you think that we missed something.

sandnabba commented 2 months ago

@rtribotte Well, yes and no. Yes it was a configuration problem that I sorted out before opening this issue. (And this particular issue seem to be very common if browsing the community forums, meaning that many people seem to misunderstand this).

So this is a feature request: I think Traefik should print a warning if a router is configured with incompatible entrypoints

kevinpollet commented 2 months ago

Hello @sandnabba,

I think Traefik should print a warning if a router is configured with incompatible entrypoints

As explained by @rtribotte, EntryPoints in Traefik are essentially ports that can have one or more HTTP and/or HTTPS routers attached to them. This means that when a request is made to a specific EntryPoint, the corresponding HTTP or HTTPS router will handle the request, depending on whether the request is made over HTTP or HTTPS.

Based on this, it doesn’t seem necessary to print a warning as there are no incompatible entrypoints.