Wednesday, 19 March 2014

Using Amazon Web Services (AWS) Elastic Load Balancers (ELB) to Server Multiple SSL Secured Applications From a Single EC2 Instance

Standard EC2 instances have the limitation that only a single IP address can be associated with each. Amazon VPC allows you to allocate more IP addresses and network interfaces, the amount depending on the instance type.

The number of additional IP's that you can add does not necessarily equal the number of SSL certificates that you can install per instance, as you will need a network interface per SSL certificate. I use VPC for one of my smaller application servers that runs a couple of low traffic websites in this way, and it works well. 

What if you want more applications per instance though, or you don't want to incur the cost of a larger instance that has the required number of network interfaces?

One option is to set up multiple Elastic Load Balancers (ELB) that each direct traffic to the same EC2 instance. The ELB can listen on multiple ports, and each of these ports can be configured to forward traffic to different port on the target instance. In addition, HTTPS can terminate at the load balancer, and subsequent communication with the EC2 instance can go over HTTP. The user of your application still has their requests handled and responded to via SSL. This feature is what enables us to run multiple applications requiring an SSL certificate on the same EC2 instance.

There are cost implications to this technique, since VPC is free to use, and ELB's incur an hourly useage charge. However as the number of SSL applications per machine increases, and the instance sizes increase, the relative cost of each additional ELB goes down in relation to the comparative cost of running multiple instances because you need the additional network interfaces.

Based on 2 SSL applications per EC2 instance:

ELB Hours = $0.025 x 24 hours = $0.60 x 30 days = $36.00

So the cost of sharing the instance for additional SSL certificates is $36.00. However each additional SSL secured application can be achieved with a single additional load balancer at $18.00, which is where this method becomes more cost effective.

In addition there may be minor application code modifications required to use your web applications in this scenario. At least one application on the instance should provide a url at which the load balancer can call to check the health of the instance (the instance will be taken offline otherwise). In my case, one application is setup to receive all traffic not routed to a specific application, and respond with a 200 OK. Also, because comms between the load balancer and the instance is always over HTTP port 80, any code that checks for https or a secure connection may need to be altered to check for a X-Forwarded-Proto HTTP header, which the load balancer will insert into the request headers indicating the original protocol used for the request (.NET C# example follows later).

In this instance, the target EC2 instance is running two ASP.NET MVC web applications running on a Windows Server 2008 R2 EC2 instance.

Step 1 - Obtain SSL Certificates for Each of The Web Applications 


In this case follow the AWS instructions AWS instructions for generating a private key and CSR. Follow the instructions up to and including "Submit the CSR to a Certificate Authority" to the point where you have received your certificate file back from your SSL certificate provider. I used openssl via Cygwin on Windows to create the private key and CSR files.

Note that we will be installing each certificate into the ELB, not IIS, so we will not be creating our CSR using IIS as you might for a normal web application running under Windows Server. If you do subsequently need to import the certificate into IIS for some reason, you can convert the certificate and private key file into a .pfx file using openssl that can be imported into IIS.

Step 2 - Create 2 ELB's (Elastic Load Balancers)


Create each of the two load balancers as below. Note that the load balancer listens on port 443, but forwards comms over plain HTTP on port 80.

Since the load balancers both exist to direct traffic to the same EC2 instance, the instance for each of the load balancers will be the single EC2 instance that is runnin both of your web applications.

On configuring the HTTPS listener, you will be prompted to upload or select an existing SSL certificate. Choose the appropriate key and certificate files so that you can paste the content into the AWS UI when prompted.

Step 3 - Check Firewalls


You are unlikely to need to do anything here, since the load balancer communicates with the web server over port 80, so port 443, 8443 etc need not be open.

Step 4 - Set Up Bindings (IIS)


To distinguish web traffic targeted at each web application, each web application should have bindings configured to handle traffic for each appropriate host. These are only special in that there is not an HTTPs binding, and no server certificate uploaded.



Step 5 - Modify Application if Required ASP.NET MVC Context


In short, application code relying on 
Request.IsSecureConnection
Becomes
Request.IsSecureConnection || string.Equals(Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase);

Basically, we are saying if the standard web framework says the connection is secure, then treat as secure, but also treat as secure if the X-Forwarded-Proto header indicates an HTTPS connection.
For the health check url that is required by the Elastic Load balancer, this can be as simple as the following:
public ActionResult Ping()
{
            return View();
}

Useful links


Another blog explaining how to set up SSL in EC2 Elastic Load Balancers

http://www.nczonline.net/blog/2012/08/15/setting-up-ssl-on-an-amazon-elastic-load-balancer/

Discussion of the X-Forwarded-Proto HTTP header in ELB context

http://aws.typepad.com/aws/2010/10/keeping-customers-happy-another-new-elastic-load-balancer-feature.html

Stack Overflow Disction of MVC Require HTTPS and X-Forwarded-Proto HTTP header

http://stackoverflow.com/questions/10131830/mvc3-requirehttps-and-custom-handler-result-in-http-310

Converting private keys and CSRs to .PFX format for IIS import (not required for ELB SSL)


Ping / Xport forwarding

No comments:

Post a Comment