2

Consider the following situation:

                                      Internet
                                         ||
                                         ||
                                  .------''------.
                                  | HTTPS (:443) |
                                  '------..------'
                                         ||
                 .-----------------------'|
                 |                       \/
                 |           3rd party HAproxy service
                 |                       ||
                 |                       ||
             optional        .-----------''-----------.
               route         | PROXY Protocol (:5443) |
                 |           '-----------..-----------'
                 |                       ||                                 ________
      ___________|_______________________||________________________________| SERVER |____
     |           |                       \/                                              |
     |           |                 local HAproxy                                         |
     |           |                       ||                                              |
     |           |                       ||                                              |
     |           |                .------''------.                                       |
     |           |                | HTTPS (:443) |                                       |
     |           |                '------..------'                                       |
     |           |                       ||                                              |
     |           |                       ||                                              |
     |           |                       \/                                              |
     |           '---------------> local webserver                                       |
     |___________________________________________________________________________________|

The backend server has both HAproxy and Apache httpd locally running on port 5443 and 443 respectively.

My local webserver does not support the PROXY protocol. So I want HAproxy to catch the PROXY Protocol from the 3rd party service, and pass the data to the local webserver in either HTTPS or simply a TCP pass-through.

In the case of HTTPS I suppose it should manipulate the HTTP packets using the correct SSL-certificate to add the original sender IP in the X-Forwarded-For HTTP headers (which should be provided by the PROXY protocol).

However, the documentation of HAproxy is awful if you are new to HAproxy, and I could not find examples that explain how to do this. I know it has to be possible since HAproxy is listed as "Proxy-protocol ready software", but how?

Yeti
  • 2,647
  • 2
  • 33
  • 37

1 Answers1

4

Yes, you need to use the accept-proxy keyword after bind in the frontend declaration. It will also be good to read about the related send-proxy keyword which is used in the given "3rd party HAproxy service".

The PROXY Protocol can be stripped back to its original state using the following HAproxy configuration:

frontend app-proxy
  bind *:5443 accept-proxy
  mode tcp
  option tcplog
  default_backend app-httpd
backend app-httpd
  mode tcp
  server app1 127.0.0.1:443 check

This will accept a PROXY Protocol on port 5443, strip it, and send the TCP data to 443.

If you would like to manipulate the HTTP packets in the SSL-encrypted TCP data, you would need to have access to the correct SSL certificates (which your webserver should have access to already). This is what you'll likely want to do.

frontend app-proxy
  bind *:5443 accept-proxy ssl crt /path/to/certnkey-file.pem
  mode http
  option httplog
  default_backend app-httpd
backend app-httpd
  mode http
  server app1 127.0.0.1:443 check ssl verify none

The advantage of the latter approach is that the original client data is preserved while passing through the proxies, so that you know what the original IP of your visitor is. Which is kind of the whole idea of using PROXY Protocol in the first place! HAproxy will automatically update the X-Forwarded-For header with the correct IP-address which was transferred using the PROXY Protocol.

Yeti
  • 2,647
  • 2
  • 33
  • 37
  • 2
    Note that any time you use the Proxy protocol, it's critical to ensure that your service will never accept requests from anything other than the trusted source, whether you do that with IP-based restrictions, TLS mutual auth, or some other mechanism, because an untrusted source can forge the Proxy protocol preamble ("headers") and thus forge its identity. This is not a vulnerability per se, it's the same with standaed `X-Forwarded-For` -- when parsing right to left, the first untrusted IP is the only value you can actually believe. Anything to the left of that may be forged. – Michael - sqlbot May 19 '18 at 21:36
  • @Michael-sqlbot Good point. But if I understand it correctly, then it doesn't matter whether you accept an imposter or not - as you can always check the validity afterwards based on the IP-addresses in the `X-Forwarded-For`. The last IP-address cannot be forged, because it is only added in the endpoint based on the TCP packet source. So even when you accept requests from an untrusted source, you can check for this afterwards by inspecting the `X-Forwarded-For`, correct? – Yeti May 20 '18 at 21:54
  • No, I don't think so, because X-Forwarded-For would contain whatever was written in the Proxy protocol message, rather than the address from the IP stack, would it not? The proxy protocol implicitly trusts the sender to send an accurate message. – Michael - sqlbot May 20 '18 at 22:16