elb
When using AWS Elastic Load Balancer with TCP listeners (not HTTP or HTTPS), the biggest problem faced by many people is the lack of client’s IP address. Since it’s TCP which works on a lower layer, the ELB does not add the X-Forwaded-For header (like it does for HTTP and HTTPS). For some time, this meant that if you used those listeners, you had no way of getting the original client’s IP address.

Why use TCP listeners at all?

Given the above, the obvious question is – why use TCP forwarding at all, and not simply use HTTP and HTTPS?
Well, first of all, internet doesn’t stop on HTTP 😉 So, for non-HTTP traffic that wants to be encrypted, you’ll need to use TCP forwarding.
Second, you may not want (or can) terminate the SSL encryption on the load balancer. Using HTTPS or SSL (Secure TCP) listeners on ELB, means the ELB deals with SSL, not your server. The traffic to your server is then send without encryption – which may not be an option for you if your business requires end-to-end encryption (personal info? credit card data? CISSP on payroll?).

So, if for any reason, you’d like to use the TCP listeners, getting the client’s IP address is tricky. It was impossible, until AWS introduced Proxy Protocol support for ELB.

Proxy Protocol in ELB

In short, it adds an additional information to each request which contains the information about the original client – their IP address and port.

It is not enabled by default when using the ELB TCP listeners and has to be added as a “policy” to ELB. Check out the links at the bottom of this post for info how to enable it using AWS CLI. What I wanted to focus on was how to enable it when using CloudFormation to create your ELB. The AWS documentation is a good resource, but because there’s a couple of different policies you can enable for ELB, some of them require different options.

So, below, CloudFormation snippets that enable the Proxy Protocol support for an ELB with TCP listeners on ports 80 and 443

"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
    "Listeners": [
                    {
                        "InstancePort": "80",
                        "LoadBalancerPort": "80",
                        "Protocol": "TCP"
                    },
                    {
                        "InstancePort": "443",
                        "LoadBalancerPort": "443",
                        "Protocol": "TCP"
                    }
                ],
    "Policies": [
        {
            "InstancePorts": [ "80", "443" ],
            "PolicyName": "EnableProxyProtocolPolicy",

If using troposphere (there’s no object for the Policies at the moment):

LoadBalancer(
    "ElasticLoadBalancer",
    ...
    Policies=[
        {
            "PolicyName": "EnableProxyProtocol",
            "PolicyType": "ProxyProtocolPolicyType",
            "Attributes": [{
                "Name": "ProxyProtocol",
                "Value": "true"
            }],
            "InstancePorts": ["80", "443"]
        }
    ]
))

Nothing else. No PolicyNames in Listener, only the above.

How do I get the client’s IP within my web server?

Enabling the policy, simply adds an additional information to each request being passed by ELB to your server. If you’re using a web server to serve the requests (like nginx or Apache), the client’s IP will not be immediately available for you – you need to tell your web server application to expect and parse that additional information.

For nginx, use something like this: https://gist.github.com/pablitoc/91c40d820f207879969c – scroll down to “Configuring NGINX to accept headers from Proxy Protocol”. This page also contains a longer explanation of the problem and has the walk-through on how to enable the Proxy Protocol via AWS CLI.

For Apache, the problem is slightly more complicated as the support is not available out of the box.. There’s a nice module written by those guys: https://technobcn.wordpress.com/2014/12/06/apache-proxy-protocol-for-amazon-elb-elastic-load-balancing/ – many kudos for that!

Links

Was this post helpful to you? Yes!


Leave a comment