Hey — I'm Jud Stephenson, @JudStephenson on Twitter. Currently co-founding Nybex. Previously @ Svpply/ebay.

October 31, 2013 at 12:36pm

Hardened SSL Ciphers Using AWS ELB and HAProxy

Perfect Forward Secrecy with remote client ip address courtesy of PROXY protocol goodness.


I stumbled across this post on /r/netsec and saw this user’s comment, looking for a way to deploy a hardened SSL cipher suite with ELB.

Having just finished setting this up for Nybex, I figured I would share our implementation. As a warning, we are doing SSL termination on our frontend instances, so if you require SSL termination to happen at the ELB, you are still out of luck.

Our basic setup looks like:

 -----      ---------      ------------
| ELB | -> | HAProxy | -> | Web Server |
 -----      ---------      ------------

The elastic load balancer proxies requests to our frontend servers, which run HAProxy for SSL termination and Unicorn. By enabling the PROXY protocol role on the ELB, the frontend servers also have access to the real remote client ip.

Enabling PROXY Protocol Support on the ELB

  • Setup a tcp listener on port 443 on your ELB (the instance port can be whatever you want)
  • Make sure you have the elb-tools installed [a simple brew install elb-tools works]

Run the following to create the policy:

elb-create-lb-policy LOADBALANCER_NAME --policy-name EnableProxyProtocol --policy-type ProxyProtocolPolicyType  --attribute "name=ProxyProtocol, value=true"

Then enable the policy for the specific instance port:

elb-set-lb-policies-for-backend-server LOADBALANCER_NAME --instance-port INSTANCE_PORT --policy-names EnableProxyProtocol

Configure HAProxy for Hardened SSL Termination

In the relevant frontend portion of your HAProxy config, modify the following to your liking.

# Bind on port 443. NOTE: accept-proxy is required here
# since the ELB is using the PROXY protocol. Also, the
# ciphers came from:
# http://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
bind accept-proxy ssl crt /etc/cert.pem ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5:!DSS

# Add X-Forwarded-Proto header
reqadd X-Forwarded-Proto:\ https

# This option will set X-Forwarded-For header to the ip
# passed along from the ELB
option forwardfor

That’s all there is to it. If you have any questions, I’m @JudStephenson on Twitter.