Configuring HTTPS for the AWS Elastic Beanstalk Load balancer

January 19, 2015


Switching your Rails site to always use HTTPS takes a bit configuring.

Here is how we followed AWS’s 3 high level steps: http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/ssl-server-cert.html

  1. Create a custom domain with your DNS provider.
  2. Create and upload an SSL certificate to AWS Identity and Access Management (AWS IAM).
  3. Update your Elastic Beanstalk environment to use HTTPS.

Step 1) was DONE - We already had our own www.ourdomain.com, not registered on AWS route 53 nor using the AWS route 53 name servers, but with godaddy.com

We initially went with a self-signed certificate until we got everything configured correctly:

Step 2) Create and upload an SSL certificate to AWS Identity and Access Management (AWS IAM):

  1. Install OpenSSL: Binary Distributions from http://www.openssl.org/related/binaries.html

    a) install Microsoft Visual C++ 2008 Redistributable Setup Wizard.

    b) select the appropriate version of the OpenSSL binaries for your environment and save the file locally. The OpenSSL Setup Wizard launches….Save the OpenSSL binaries to a folder in your working directory.

    c) set PATH for OpenSSL_HOME variable

  2. Create a Private Key & Certificate Signing Request (CSR) and generate a self-signed certificate. ( for now )

  3. Upload the Signed Certificate

Step 3) Update your Elastic Beanstalk environment to use HTTPS:

a) Install the AWS Command Line Interface, and configure it. b) upload certificate: aws iam upload-server-certificate –server-certificate-name ourdomain-com-cert –certificate-body file://ourdomain-com-cert.crt –private-key file://privatekey.pem c) update EB load balancer

  1. to use HTTPS port 443, not HTTP,
  2. change security group inbound to use port 443 not 0.0.0.0/0;
  3. copy ARN to SSL certificate ID

That all appeared to work until we navigated off the default page, and then it didn’t. So we spun up a test EB environment and pushed a code change with config.force_ssl added to config/environments/production.rb - and that broke stuff. ‘health check’ wasn’t happy and the https url didn’t even hit the server according to the logs.

To fix the routing we had to go back to the DNS registrar and change forwarding from http://www.ourdomain.com to https://www.ourdomain.com; and in the zone file CNAME we added the ‘https’ host.

To make ‘health check’ happy we reverted the config.force_ssl code change, and instead pushed this change to the application_controller.rb:

force_ssl if: :ssl_required?</code>

private

  def ssl_required?
    # If request came in *through* the load-balancer, this header will be present
    if request.headers['X-Forwarded-Proto'].present? &amp;&amp; !request.ssl? &amp;&amp; Rails.env.production?
      return true
    end
    # We came *from* the LB, ie this is a health check, so no ssl required.
    return false
  end

At this point the https:// is marked with a red cross because we self-certified.

Getting & installing the certified SSL certificate:

sslmate is the way to go, but you have to go the extra mile to get it installed on windows: https://sslmate.com/help/getting_started#install

To get ‘cpan’ working on windows, download and install Strawberry Perl 5.20.1.1 (64bit) - from http://strawberryperl.com

Have it configure itself, which takes 6 minutes. At the point where we were ready to buy a certificate with sslmate’s command line, we saw godaddy offering a certificate for £3.99 so we went with that. We can come back to these notes after 12 months and use sslmate for the renewal @ $15.

So download the certificate from godaddy, selecting the apache server format option; and upload to AWS IAM using the AWS command line tool again, point the LB at the new certificate arn, and success! we get the green https padlock. Time to terminate the test EB environment and apply updates to the production EB load balancer.

On some pages the green https padlock is marked with a yellow triangle warning as there are a few components that use the http host instead https. So once we track those down and push fixes we are done.

2016 update: Certificate creation is now free with AWS Certificate Manager. Going forward this is the route we are taking.

2017 update: The free certificates issued by AWS are only available by reference, that is you can not get the single instance NGINX config to see the contents of the PEM-encoded certificate body, private key, and certificate chain. Instead we now use Let’s Encrypt Automatic SSL Certificate Renewal, which is free and can be automated. The blog post is here: Let’s Encrypt Automatic SSL Certificate Renewal on a single AWS instance.

© 2018 Keith P | Follow on Twitter | Git