Proxy Protocol V1

I recently got to know Proxy Protocol as the result of a particular intersection of requirements.

  1. I wanted to terminate HTTPS on my AWS instances but leverage ELB's for improved availability.

  2. I wanted to be able to make use of a combination of client IP address and request path in the access control configuration of my web server.

Terminating HTTPS on your web server through an ELB is no problem, ELB supports a TCP mode. However, as a generic TCP proxy, an ELB has no way to communicate with the web server about the client connection inforation. If I was using the ELB as an HTTP proxy, my server could get that information out of the X-Forwarded-For header. This is where Proxy Protocol comes in.

When configured to use Proxy Protocol, an ELB will first send a line containing connection information to the web server. The webserver needs to have support for Proxy Protocol itself, othewise it will fail to understand the first line and will drop the connection or otherwise behave badly. Proxy protocol isn't backward compatible with HTTP and certainly not with SSL.

Unfortunately very few servers support Proxy Protocol. Apache, the server I was using, is not one of those that does. Haproxy 1.5 does support Proxy Protocol, and it is flexible enough for my purposes.

When possible, to simplify configuration management, I like to install third-party software by means of yum from standard repositories. Sadly, I did not find a pre-built RPM for haproxy 1.5 on CentOS 6. I ended up compiling haproxy1.5 with support for SSL using the following command from the README in the source tarball:

make TARGET=linux2628 CPU=native USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1

I use CloudFormation to build my ELB's. Amazon's documentation provides a code snippet to show how to set the ELB to use Proxy Protocol in your CloudFormation template. It ends up something like this:

"Policies" : [{
   "PolicyName" : "EnableProxyProtocol",
   "PolicyType" : "ProxyProtocolPolicyType",
   "Attributes" : [{
      "Name"  : "ProxyProtocol",
      "Value" : "true"
   }],
   "InstancePorts" : ["443"]
}],

It doesn't seem possible to turn Proxy Protocol support on in the AWS console, so if you're not using cloudformation, you'll need to use the command line client to enable Proxy Protocol.

With haproxy terminating the HTTPS connection, the client IP of the client rather than an internal IP of the ELB shows up in the logs and can be used for access controls.

I often want to be able to test my servers from the local host when troubleshooting. I also like to be able to make a quick sanity check of a server when I first bring it online. Something like curl -k -I https://localhost/. Curl doesn't have support for Proxy Protocol, so that doesn't work for me any more. Instead I get:

$ curl -k -I https://localhost/
curl: (35) SSL connect error

To ease my mind, I created a crude test client for Proxy-Protocol-fronted HTTP(S) servers. With ppcurlcat I can do a sanity test like the following:

$ ppurlcat.py https://localhost/ | head -1
HTTP/1.1 200 OK

It looks like a higher level test would be practical. With the requests module, for example, I found this information on how to make requests on an existing socket. Conceptually, I suppose it doesn't make sense to build proxy protocol support directly into an http client library.

comments powered by Disqus