crowdsecurity / cs-haproxy-bouncer

Crowdsec bouncer for HAProxy
MIT License
18 stars 7 forks source link

Issue with loop in HAProxy config #13

Closed ciphermenial closed 1 year ago

ciphermenial commented 1 year ago

See this discourse post for more information.

I was trying to figure out how the IPs were detected but had no luck.

LaurenceJJones commented 1 year ago

We use haproxy function to return the source_ip https://github.com/crowdsecurity/cs-haproxy-bouncer/blob/abb4f1de1f0bdedd358dbfb21f9c34e1ac6c4145/lib/crowdsec.lua#L127 Guess the src ip is getting confused with "internal users" since you have a http proxy infront.

ciphermenial commented 1 year ago

I am asking in the HAProxy discourse now. forwardfor works to show the correct IP in all my web services so I am guessing I should be able to get it working.

ciphermenial commented 1 year ago

This works to detect the correct IP. I replaced local source_ip = txn.f:src() with:

    local source_ip

    source_ip = txn.f:req_fhdr("CF-Connecting-IP")
    if (source_ip == nil) then
        source_ip = txn.f:src()
        if (source_ip == nil) then
            return default;
        end
    end

in the crowdsec.lua file.

This detects it correctly but then I have a loop in the captcha. It pops up over and over.

LaurenceJJones commented 1 year ago

Hmm guess haproxy does not automatically enforce forwarded headers.... might be best if we configure this in the lua part. Okay, so you get catcha -> solve -> captcha again?

Just checking if your configuration has these settings https://docs.crowdsec.net/docs/next/bouncers/haproxy#haproxy-configuration

Edit: so you need to be careful as blinding accepting x-forwarded-for can lead to spoofing attacks you need to set who you trust. Here is a snippet from cloudflare configuration to get the realip. So you can tailor it depending if they can from cloudflare or your internal proxy.

Restoring original visitor IP with HAProxy

In order to extract the original client IP in the X_FORWARDD_FOR header, you need to use the following configuration in HAProxy:

    Create a text file CF_ips.lst containing all IP ranges from https://www.cloudflare.com/en-gb/ips/
    Ensure to disable option forwardfor in HAProxy

HAProxy config:

acl from_cf src -f /path/to/CF_ips.lst

acl cf_ip_hdr req.hdr(CF-Connecting-IP) -m found

http-request set-header X-Forwarded-For %[req.hdr(CF-Connecting-IP)] if from_cf cf_ip_hdr

Do note however, you should set your haproxy to only accept connections from cloudflare or your internal proxy.

ciphermenial commented 1 year ago

My firewall only accepts connections in from CloudFlare.

If I use the normal crowdsec.lua and do a decision based on 127.0.0.1, the captcha works correctly. If I make the change as above it keeps looping after the solve.

ciphermenial commented 1 year ago

I have it working now. I changed a line in haproxy.cfg

I changed http-request track-sc0 src if { var(req.remediation) -m str "captcha-allow" } to http-request track-sc0 req.hdr_ip(CF-Connecting-IP,-1) if { var(req.remediation) -m str "captcha-allow" }

ciphermenial commented 1 year ago

Thanks for pointing me in the right direction for using CF-Connecting-IP header. I have now fixed up my haproxy config to use that by default.

Would there be a way to add a variable to crowdsec-haproxy-bouncer.conf to detect IP based on a header rather than src?

I believe this would be something a lot of people would find useful.

ciphermenial commented 1 year ago

I have created a pull request with what I believe should resolve this issue. #14

LaurenceJJones commented 1 year ago

Updating issue with findings:

We don't want to handle trusted headers / trusted IP's via bouncer configuration as it messy, introduces too many vulnerability such as spoofing.

So what we recommend is to use HAproxy in built methods to set the src_ip to the headers you trust from the IP's you trust, an example configuration for cloudflare is

  acl from_cf src -f /etc/haproxy/cf-ips/cf-ips
  http-request set-src req.hdr(CF-Connecting-IP) if from_cf

/etc/haproxy/cf-ips/cf-ips contains a list of cloudflare IP's to which then haproxy will set the src from the header CF-Connecting-IP which then the lua code will have the correct IP