Dead simple SSL with AWS Load Balancers and Certificate Manager

Nov 14, 2017

Managing SSL certificates sucks. If you’re lucky, you only have to set it up once. However, if you’re working on a horizontally scaled stack, chances are you’re going to need to configure more servers with SSL and HTTP -> HTTPS redirects.

In a horizontally scaled web server environment, no individual server should care about SSL. Your customers and the rest of the world should interact with your system through HTTPS, but your web servers only need to respond to HTTP, to allow for per-server health check monitoring.

Your load balancer is the bridge between your pool of resources and the outside world, so your load balancer should handle SSL. Luckily, AWS makes this really easy.

Configuring your certificate

AWS provides a very useful service called Certificate Manager (ACM), which allows you to store your SSL/TLS certificates for easy deployment to AWS resources. ACM also provides free SSL/TLS certificates (even wildcard certs).

From your AWS console, Import or Request a certificate in ACM.

Configuring your load balancer

I’m going to assume that you already have a load balancer set up in AWS. If not, AWS’s official documentation has a tutorial. This guide should work with both classic Elastic Load Balancers and the new Application Load Balancers.

In the EC2 dashboard, select your load balancer configuration, and click the Listeners tab, then click Edit. Now, we’re going to add a new listener to forward external HTTPS traffic to each instance as HTTP traffic. Use the following configuration:

Load Balancer Protocol: HTTPS

Load Balancer Port: 443

Instance Protocol: HTTP

Instance Port: 80

SSL Certificate: Choose the certificate you set up earlier in ACM.

With this new listener, we’ve enabled HTTPS traffic to your pool of web server resources without writing a single line of Nginx or Apache configuration, or dealing with securing a SSL/TLS certificate or private key on each web server.

However, one thing we’re missing is a proper way to handle inbound HTTP traffic and send it to where it ought to be, HTTPS! Unfortunately AWS doesn’t offer a built-in way to do this with their load balancers, so we’ll have to work with the web servers directly.

Configuring the redirect pass-through

To easily and simply handle the redirection of HTTP to HTTPS traffic, we’re going to use something that I call the redirect pass-through.

Since the load balancer is terminating the SSL connection and passing off traffic to the instance on port 80, we want to easily differentiate traffic that should be served a web page and traffic that should be redirected to HTTPS.

In your load balancer configuration, update the HTTP listener (port 80) to forward traffic to the instance on port 81. This is the redirect pass-through port.

On each instance, add a new Nginx site with the following configuration:

server{listen81;rewrite^https://$host$request_uri?permanent;}

Thats it! Now, you can interact with the web server directly on port 80, the web server will serve traffic to HTTPS requests through the load balancer on port 80, and the server will redirect requests to HTTPS using the new redirect pass-through port.