2016-08-02

3 Steps to Free SSL for your domain's static website on AWS S3

Today, let's talk about upgrading your static web site --- served from your own domain --- so that it serves over HTTPS secure protocol.

Prerequisites
This post assumes you've got certain things already set up. If you don't, the rest of this post won't help you, sorry.

(1) You must already have a static web site served from Amazon Web Services (AWS) S3.

But really, if all you've got is just a static web site (no dynamic content, no server side scripts, no database, etc.), using S3 is pretty awesome.  It's fast, inexpensive, and pretty easy to set up --- a topic for another day perhaps.

(2) You must already have your own domain name set up for your web site, e.g. from Namecheap, and you're a little comfortable setting up custom "Advanced DNS" records like CNAME records, etc.  Again, if you don't, the following won't help you, sorry.

NameCheap's been pretty fantastic for domain name and DNS services for me.  Great service.

(3) You also must have email set up for your domain name.  Maybe you've got email set up with that domain name from your domain name registry (e.g. Namecheap).  Or maybe you've got it set up with a dedicated email hosting service, e.g. Fastmail.com, or Google Apps for Work.

Strategy
The general ideas are these:
  1. Get a free SSL / TLS certificate for your domain name from AWS Certificate Manager (ACM)
  2. Create an AWS Cloudfront Distribution to originate content from S3, to be served out on a Cloudfront address.
  3. Change your domain name's DNS CNAME record to point to that Cloudfront address.



Steps
Let's assume we're working with your web domain:  example.com.

(Step 1) Get a free SSL / TLS certificate

(1.1) If you're at a machine with AWS Command Line Interface set up, this step is easy.  If you don't, go install it now, I'll wait.

(1.2) Alright, if you're on a Mac or Linux machine, from the terminal, do this:

$ export AWS_DEFAULT_REGION=us-east-1

$ aws acm request-certificate --domain-name www.example.com --subject-alternative-names "example.com"

The export line ensures the certificate is created in AWS's US-East-1 region.  That's the only region Cloudfront will let you pick certificates from later.

The aws acm command requests a certificate, obviously.  Note the main domain-name is the www one.

If you value having email working after all this, I suggest setting your web site up on the "www.example.com" sub-domain and having your "naked domain", i.e. "example.com" redirect (i.e. frameless 301 or 302 redirect) to the www one instead (just for convenience of your web audience).

(1.3) You'll need to go to your email and click Approve on the AWS Certificate Approval emails before moving on.

The approval emails will be sent to the email address in the WHOIS file for your domain.  For many of us that are privacy minded, if you have WHOIS privacy services hiding your email addresses, this step will fail - but there is an alternative:

The alternative to WHOIS emails is to ensure your domain has one of these email addresses set up (c.f. ACM FAQ on "To which email addresses is the approval request sent"):
  • postmaster@example.com
  • administrator@example.com
  • admin@example.com
  • hostmaster@example.com
  • webmaster@example.com
You really should have postmaster@ set up as it's a required email address to have according to an internet specification for email.

Note: AWS ACM doesn't let you download the private key for the certificates it creates for you. That's the price for it being free I guess.

But if you want your own free certificate, private key and all, you should be able to get one from Let's Encrypt.  With that certificate in hand, you should be able to upload it to AWS ACM and the next two steps are the same.


(Step 2) Create an AWS Cloudfront Distribution

Go ahead to AWS CloudFront admin panel and create a new distribution.

Most of the default settings for creating a new CloudFront Distribution is okay, except a few key modifications to be noted below:

Origin:
Pay attention because setting this wrong costed me a lot of time.  Do NOT choose any of the options in the drop-down menu there (those are so convenient, and yet so wrong...).

Instead, find your "S3 website endpoint" for the S3 bucket that you use to hose your static web site.  You can find that in your S3 bucket's "Properties" panel under "Static Website Hosting" option).  Note that this is NOT your S3 bucket's endpoint address.  The website endpoint has the form:
www.example.com.s3-website-us-east-1.amazonaws.com
Type that into your Cloudfront Distribution's Origin (c.f. AWS's guide step 4).

Viewer Protocol Policy:
I suggest setting this to "Redirect HTTP to HTTPS" to take advantage of HTTPS everywhere on your site.

Compress Objects Automatically:
I suggest setting to "Yes".  Apparently CloudFront charge by the bytes transferred, so enabling compression should be better.

Price Class:
The more "worldwide" you go, the more expensive apparently.  If you primarily serve US and Europe audience (say it's a local audience web site), you might choose just to target US and Europe here.

One must wonder though, if by "United States" they mean also Mexico and Canada... anyway.

Alternate Domain Names (CNAMEs):
Put in on separate lines all the domains you included in the SSL certificate you requested.  For the above example, we'd put:
www.example.com
example.com 
SSL Certificate:
Select "Custom SSL Certificate" and from the drop-down menu, choose the certificate you requested before.  If this is your first time, there should only be one to choose from anyway.


(Step 3) Change your domain name's DNS CNAME record to point to Cloudfront address

I don't know anything about using AWS Route 53 because I like to keep my domain name and DNS separated on NameCheap (or GoDaddy or whatever).  Regardless...

(3.1) Note down your custom CloudFront Distribution address.

It's under the "Domain Name" column of your CloudFront Distribution admin screen.  It has the form of something like:
mno3pqr4stu5.cloudfront.net
Go to your domain service's Advanced DNS settings page to create a CNAME record for your www.example.com host to point to the above noted ___.cloudfront.net domain.

If you want your bare "naked domain" (example.com) to automagically go to your web site in the web browser, create a "redirect" record for it to forward to your www host instead.  That way, you can still set up email MX records for your example.com domain --- otherwise your email will stop working.

"URL Redirect Record" are variously named "Unmasked-", "Frameless-", "Masked-", "Frame-", "301 permanent-", etc. by various companies.  Topic for another post...

Now we wait...
CloudFront Distribution can take up to 3 hours to set up, but probably less.  Your DNS records may take up to 3 days to propagate globally, but most likely will start working for you in as soon as a few minutes.

Once those are finished processing your requests, you should be able to go to example.com and it'll redirect to www.example.com, which will look up your CloudFront distribution, which will redirect to HTTPS, which will finally connect to your S3 static web site content securely.

References:
  1. Setting Up SSL on AWS CloudFront and S3
  2. Using Amazon S3 + CloudFront + Certificate Manager to get seamless static HTTPS support
  3. Free SSL With Amazon’s AWS Certificate Manager (ACM) 
  4. Enable HTTPS with AWS Certificate Manager, CloudFront, and S3

No comments: