Skip to content
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

Traefik Routing: Protocol and Port Mismatch Not Captured #10818

Closed
2 tasks done
creativestate opened this issue Jun 16, 2024 · 2 comments
Closed
2 tasks done

Traefik Routing: Protocol and Port Mismatch Not Captured #10818

creativestate opened this issue Jun 16, 2024 · 2 comments
Labels
kind/question a question

Comments

@creativestate
Copy link

Welcome!

  • Yes, I've searched similar issues on GitHub and didn't find any.
  • Yes, I've searched similar issues on the Traefik community forum and didn't find any.

What did you do?

I've encountered an issue with Traefik where it does not properly capture and route requests with mismatched protocols and ports (e.g., HTTP on port 443 or HTTPS on port 80). Despite having rules configured for these scenarios, Traefik fails to handle them correctly, resulting in 404 errors.

A full breakdown can be found in this Forum Post: https://community.traefik.io/t/traefik-routing-issue-protocol-and-port-mismatch-not-captured-correctly/23184

What did you see instead?

404 Not Found errors for mismatched protocol and port requests.

What version of Traefik are you using?

Version: 3.0.2
Codename: beaufort
Go version: go1.22.4
Built: 2024-06-10T14:38:51Z
OS/Arch: linux/amd64

What is your environment & configuration?

http:
  routers:
    # Blackhole direct IP address requests for HTTP
    web-block-ip-router:
      rule: "HostRegexp(`^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(:[0-9] )?$|^\\[[0-9a-fA-F:] \\](:[0-9] )?$|^[0-9a-fA-F:] (:[0-9] )?$`)"
      entryPoints: ["web"]
      service: blackhole-service
      priority: 99999

    # Blackhole direct IP address requests for HTTPS
    websecure-block-ip-router:
      rule: "HostRegexp(`^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(:[0-9] )?$|^\\[[0-9a-fA-F:] \\](:[0-9] )?$|^[0-9a-fA-F:] (:[0-9] )?$`)"
      entryPoints: ["websecure"]
      service: blackhole-service
      tls: {}
      priority: 99999

    # Blackhole mismatched entry and request
    web-portweb-webentry-mismatch:
      entryPoints: ["web"]
      rule: "HostRegexp(`^(http:\\/\\/|https:\\/\\/)?[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(:80|:443)?$|^(http:\\/\\/|https:\\/\\/)?\\[[0-9a-fA-F:] \\](:80|:443)?$|^(http:\\/\\/|https:\\/\\/)?[0-9a-fA-F:] (:80|:443)?$`)"
      service: blackhole-service
      priority: 99998

    # Blackhole mismatched entry and request
    web-portweb-websecureentry-mismatch:
      entryPoints: ["websecure"]
      rule: "HostRegexp(`^(http:\\/\\/|https:\\/\\/)?[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(:80|:443)?$|^(http:\\/\\/|https:\\/\\/)?\\[[0-9a-fA-F:] \\](:80|:443)?$|^(http:\\/\\/|https:\\/\\/)?[0-9a-fA-F:] (:80|:443)?$`)"
      service: blackhole-service
      tls: {}
      priority: 99998

    # Blackhole non-matching cert domains for HTTP
    web-block-non-matching-cert-domains:
      rule: "!HostRegexp(`^redacted\\.com(:[0-9] )?$|^.*\\.redacted\\.com(:[0-9] )?$|^.*\\.dev\\.redacted\\.com(:[0-9] )?$|^.*\\.beta\\.redacted\\.com(:[0-9] )?$`)"
      entryPoints: ["web"]
      service: blackhole-service
      priority: 10

    # Blackhole non-matching cert domains for HTTPS
    websecure-block-non-matching-cert-domains:
      rule: "!HostRegexp(`^redacted\\.com(:[0-9] )?$|^.*\\.redacted\\.com(:[0-9] )?$|^.*\\.dev\\.redacted\\.com(:[0-9] )?$|^.*\\.beta\\.redacted\\.com(:[0-9] )?$`)"
      entryPoints: ["websecure"]
      service: blackhole-service
      tls: {}
      priority: 10

    # Block match cert domains if HTTP
    web-block-matching-cert-domains:
      rule: "HostRegexp(`^redacted\\.com(:[0-9] )?$|^.*\\.redacted\\.com(:[0-9] )?$|^.*\\.dev\\.redacted\\.com(:[0-9] )?$|^.*\\.beta\\.redacted\\.com(:[0-9] )?$`)"
      entryPoints: ["web"]
      service: blackhole-service
      priority: 5

    # Block match cert domains if HTTP
    websecure-block-matching-cert-domains:
      rule: "HostRegexp(`^redacted\\.com(:[0-9] )?$|^.*\\.redacted\\.com(:[0-9] )?$|^.*\\.dev\\.redacted\\.com(:[0-9] )?$|^.*\\.beta\\.redacted\\.com(:[0-9] )?$`)"
      entryPoints: ["websecure"]
      service: blackhole-service
      tls: {}
      priority: 5

    # Default path rule for HTTP
    web-block-default:
      rule: "PathPrefix(`/`)"
      entryPoints: ["web"]
      service: blackhole-service
      priority: 1

    # Default path rule for HTTPS
    websecure-block-default:
      rule: "PathPrefix(`/`)"
      entryPoints: ["websecure"]
      service: blackhole-service
      tls: {}
      priority: 1

    # Catch-all rule for HTTP
    web-catch-all:
      rule: "HostRegexp(`.*`)"
      entryPoints: ["web"]
      service: blackhole-service
      priority: 0

    # Catch-all rule for HTTPS
    websecure-catch-all:
      rule: "HostRegexp(`.*`)"
      entryPoints: ["websecure"]
      service: blackhole-service
      tls: {}
      priority: 0

  services:
    blackhole-service:
      loadBalancer:
        servers:
          - url: "http://10.255.255.1"

Add more configuration information here.

If applicable, please paste the log output in DEBUG level

For https://<load_balancer_ip>:80:
2024-06-15T08:43:06 10:00 DBG github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:228 > Serving default certificate for request: ""
{"ClientAddr":"<private_ip>:53488","ClientHost":"<private_ip>","ClientPort":"53488","DownstreamStatus":404,"Duration":202631,"OriginStatus":0,"RequestAddr":"<load_balancer_ip>:80","RequestCount":6,"RequestHost":"<load_balancer_ip>","RequestMethod":"GET","RequestPath":"/","RequestPort":"80","RequestProtocol":"HTTP/1.1","RequestScheme":"https","RetryAttempts":0,"StartLocal":"2024-06-15T08:43:06.962840543 10:00","entryPointName":"web","level":"info","msg":"","request_User-Agent":"curl/7.68.0"}

For http://<load_balancer_ip>:443:
{"ClientAddr":"<private_ip>:53454","ClientHost":"<private_ip>","ClientPort":"53454","DownstreamStatus":404,"Duration":119671,"OriginStatus":0,"RequestAddr":"<load_balancer_ip>:443","RequestCount":13,"RequestHost":"<load_balancer_ip>","RequestMethod":"GET","RequestPath":"/","RequestPort":"443","RequestProtocol":"HTTP/1.1","RequestScheme":"http","RetryAttempts":0,"StartLocal":"2024-06-15T08:58:37.535011194 10:00","entryPointName":"websecure","level":"info","msg":"","request_User-Agent":"curl/7.68.0"}

@juliens
Copy link
Member

juliens commented Jul 30, 2024

Hello,

Thank you for raising this issue and I apologize for the delay in responding.

It appears that Traefik returning a 404 status code when accessed via HTTPS on port 80 and HTTP on port 443 is normal.

This behavior is due to the fact that Traefik does not differentiate between protocols based on port numbers. Traefik allows for multiplexing of HTTP, HTTPS, and other TCP protocols on any given entrypoint. As a result, it's currently not possible to block a specific protocol on a particular entrypoint.

We understand that this can be a bit confusing and may not align with some users' expectations of strict protocol-port binding. However, the flexibility of allowing multiple protocols on a single entry point is by design, to provide more versatility in handling various traffic types.

To help manage this behavior, here is a configuration that can address your specific needs.

tcp:
  routers:
    # router at the TCP level which redirect non-tls request to a blackhole on the websecure entrypoint
    block-http-https:
      entryPoints: ["websecure"]
      rule: HostSNI(`*`)
      priority: 0
      service: blackhole
    # router at the TCP level which redirect tls request to a blackhole on the web entrypoint 
    block-https-http:
      entryPoints: ["web"]
      rule: HostSNI(`*`)
      priority: 0
      service: blackhole
      tls: {}

  services:
# a blackhole service which redirect request to a non existing port
    blackhole:
      loadBalancer:
        servers:
          - address: "127.0.0.1:99999"

http:
  routers:
    https-router:
      rule: "Host(`demo.localhost`)"
      entryPoints: ["websecure"]
      service: my-service
      tls: {}

    http-router:
      rule: "Host(`demo.localhost`)"
      entryPoints: ["web"]
      service: my-service


  services:
    my-service:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8080"

@juliens juliens closed this as completed Jul 30, 2024
@juliens juliens removed their assignment Jul 30, 2024
@creativestate
Copy link
Author

Hi @juliens,

Thank you for the detailed explanation of this, and appreciate a working example, can confirm this worked.

However, I noticed this approach does not log the request as a normal request in the access log, instead I see an error being thrown in the Traefik log.

The following is generated:

ERR Error while dialing backend error="dial tcp: address 99999: invalid port"

I understand because this is not a valid Traefik configured port and is the reason the error is thrown. But should it not log the request in the access log by default as this is still a "valid" incoming request except the port it is redirecting to an invalid port and Traefik is not handling this as we expect - sure this is likely by design (error handling for invalid ports), but there are numerous queries about achieving the same result as this issue was raised as, while this solution works - it is not a complete solution as we cannot capture the request via the access log using this method.

I need to be able to log all incoming requests good or bad in my access log, I do not want a port redirect (to an non-existent port) to invalidate the request (and throw an error), preventing the request from being logged as the incoming request was somewhat "valid".

When I configure the redirect port to 65535 (max allowed configurable port number) for example and set the blackhole 127.0.0.1:65535, I get a 404 in the access log, which does not operate the same as the invalid 99999 port does, the invalid port works as intended but logging as an error which is not intended.

Ultimately attempting to avoid a 404 error and capturing the request in the access log.

Many Thanks...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/question a question
Projects
None yet
Development

No branches or pull requests

3 participants