Blocking non-cloudflare proxied requests

Is it possible to not allow connections when typing in hosted IP? For example, in my access log I see a lot of connections with no router shown. When I access my site using the proper url, the correct router is shown.

35.216.244.6 - - [19/Oct/2022:19:56:31 -0400] "GET /info.php HTTP/1.1" 404 19 "-" "-" 388 "-" "-" 0ms
68.183.38.167 - - [19/Oct/2022:20:01:02 -0400] "GET /ab2g HTTP/1.1" 404 19 "-" "-" 389 "-" "-" 0ms
68.183.38.167 - - [19/Oct/2022:20:01:03 -0400] "GET /ab2h HTTP/1.1" 404 19 "-" "-" 390 "-" "-" 0ms
68.183.38.167 - - [19/Oct/2022:20:01:07 -0400] "GET / HTTP/1.1" 404 19 "-" "-" 391 "-" "-" 0ms
68.183.38.167 - - [19/Oct/2022:20:01:07 -0400] "GET / HTTP/1.1" - - "-" "-" 392 "-" "-" 0ms
my.ip.is.here - - [19/Oct/2022:20:22:53 -0400] "GET /made/up/webpage HTTP/2.0" 404 43 "-" "-" 783 "portainer@docker" "http://172.18.0.45:9000" 18ms
my.ip.is.here - - [19/Oct/2022:20:22:53 -0400] "GET /favicon.ico HTTP/2.0" 404 43 "-" "-" 784 "portainer@docker" "http://172.18.0.45:9000" 8ms

I'm guessing the other connections without a router are a bot or something trying https://ser.ver.ip.here/info.php because that is the only way I can recreate log with no router. Going to the IP like this will produce a 404 page not found.
I thought this could be avoided using client authentication, but I guess I don't understand, or I'm making it too hard. Is it possible to not allow this type of request to pass cloudflare somehow?

You can try using strict-sni-checking

It won't stop someone directly connecting and then sending a server_name in the TLS handshake but it will greatly reduce what you are seeing.

To allow only proxied requests you'd have to use some other restriction.

Even when using client authentication, you will still see entries in the Traefik access log. When using browser-supported user/pass, you would usually first see a request with error 401 ("Unauthorized"), telling the browser to ask for user/pass, then 403 ("Forbidden") when wrong user/pass is supplied.

The Internet is a the new wild west, you will continuously see requests to your server using IP only, actors are permanently scanning the net for vulnerabilities or unprotected data.

I have strict-sni-checking in my tls options doesn't seem to help.

tls:
  options:
    modern:
      minVersion: VersionTLS13
      cipherSuites:
        - ...
      curvePreferences:
        - ...
      sniStrict: true
      preferServerCipherSuites: true
      clientAuth:
        caFiles: /etc/cf_origin_pull_ca.pem
        clientAuthType: RequireAndVerifyClientCert

I guess what traefik is doing is correct. It won't allow connections from non-cloudflare. I think I was just expecting it to not log or even be non-existant to those types of connections. It just causes a lot of noise in fail2ban.

Do you have a non-tls router too? You should not be seeing any request with strict sni as the connection does not get past the handshake.

It is conceivable they are sending the host in the handshake to the , but seems like too much effort for this scanning.

@cakiwi I'm a bit unsure about that honestly. The TLS portion of my docker-compose is as follows:

      - --accesslog.filepath=/var/log/access.log
      - --accesslog.filters.statuscodes=400-499
      - --accesslog.fields.names.StartUTC=drop
      - --accesslog.fields.headers.names.RouterName=keep
      - --log.level=DEBUG #DEBUG INFO WARN ERROR PANIC FATAL
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls.certresolver=cloudflare
      - --entrypoints.websecure.http.tls.options=modern@file
      - --entrypoints.websecure.http.tls.domains[0].main=my.site
      - --entrypoints.websecure.http.tls.domains[0].sans=*.my.site

My services have labels that look generally like this:

    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`$DOMAINNAME`,`www.$DOMAINNAME`)
      - traefik.http.routers.whoami.entrypoints=websecure
      - traefik.http.routers.whoami.middlewares=secHeaders@file #,authelia-mw@file
      - traefik.http.routers.whoami.tls=true

but not every service has the tls=true ATM. Do I need to add the specific line - traefik.http.routers.whoami.tls=true to each service or can I somehow add it to the websecure so every service uses that. The TLS documentation is a bit confusing to me and I'm unsure if that specific line is redundant when TLS is defined on the entrypoint.

You can restrict more with IPWhiteList middleware.

It's not dynamic yet, but you can generate it dynamically with a (bash) cronjob like this:

IPS=$(curl https://www.cloudflare.com/ips-v4 --fail) &&
IPSLEN=$(echo $IPS | wc -w) && test $IPSLEN -gt 2 && \
cat <<EOF > /tmp/cloudflare-ips.yaml
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: cloudflare-ipwhitelist
  namespace: traefik
spec:
  ipWhiteList:
    ipStrategy:
      depth: 0
    sourceRange:
$(for ip in $IPS; do echo "      - $ip"; done)
EOF

kubectl -n $${NAMESPACE} delete middleware cloudflare-ipwhitelist || echo 1 && \
kubectl -n $${NAMESPACE} apply -f /tmp/cloudflare-ips.yaml

As an alternative, you can also use Authenticated Origin Pull.

I don't think my intent is very clear. I think all of these suggestions are correct for dening requests from random scans of my webservers IPs.

However, after doing more reading I think what I was actually looking to solve is something more like the 444 status code seen on nginx. Meaning the request would be dropped, rather than denied.

I don't think this is possible at the moment in traefik?

How nginx processes a request

How to prevent processing requests with undefined server names

If requests without the “Host” header field should not be allowed, a server that just drops the requests can be defined:

    server {
        listen      80;
        server_name "";
        return      444;
    }

Here, the server name is set to an empty string that will match requests without the “Host” header field, and a special nginx’s non-standard code 444 is returned that closes the connection.