James Mahoney

storyclub phase 6 - https

May 16th 2019

If you're hosting a website on S3 what you're doing is telling people who want www.storyclub.co.uk to hit an Amazon web server which is running a web app that knows how to load objects from S3. It returns these to the user, setting any necessary HTTP headers so that the user's browser can render it correctly.

In order to use HTTPS, you need to use CloudFront. Now what's happening is that users after www.storyclub.co.uk are sent to a CloudFront web server instead, and this is running a web app that knows how to talk to that first Amazon web server to grab the content.

One of the main features of CloudFront is to act as a content delivery network - a great big cache to avoid hitting S3 everytime a user loads a web page.

The focus of this article is using CloudFront for its HTTPS support.

This is a three step process

  1. Set up a certificate for www.storyclub.co.uk
  2. Create a CloudFront distribution
  3. Alter the DNS, so that we point to randomname-cloudfront.amazon.com, instead of randomname-s3.amazon.com

1 - Setting up a site certificate

You need the Certificate manager

Create certificates in the North Virgina (us-east-1) region

CloudFront can only use certificates from this region

Two ways to verify the certificate

  1. DNS verification. This involves monkeying around with DNS settings to prove that you own the domain.

    A fear of DNS monkeying made me pick option 2.

  2. Email verifcation. Certificate manager sends an email to something@storyclub.co.uk. The assumption is that if you own that domain you'll receive the email, and can click on the link to verify the certificate request...

What if you haven't set up email for your domain?

Over to Simple Mail Service we a go!

  1. Verify your email domain first. By monkeying around with DNS.

    Fortunately the SES console handled all of this seemlessly. So seemlessly that DNS monkeying was probably the way to go for certificate verification too. Ah well, I've been wanting to play around with SES...

  2. Do something with emails.

There's a nice feature of SES that lets you capture incoming emails and write them to S3 storage. So that's what I did. Check out the screenshot for the settings you need.

SES screenshoot

I created a new S3 bucket - mail.storyclub.co.uk

The most important step is to grant SES permission to this bucket

Do this against the S3 bucket, not using IAM.

Here's the policy JSON from the docs

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowSESPuts",
            "Effect": "Allow",
            "Principal": {
                "Service": "ses.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::BUCKET-NAME/*",
            "Condition": {
                "StringEquals": {
                    "aws:Referer": "AWSACCOUNTID"
                }
            }
        }
    ]
}

Get AWSACCOUNTID by clicking on your user name at the top right, and then "My Security Credentials". Then what you need is "Account identifiers".

Remove any hypens from your AWS Account ID when adding it to the policy JSON

2 - Create CloudFront distribution

Too many settings to document, but these are the important ones

  • Origin Domain Name - choose your bucket

    This defaults to the REST endpoint, meaning you have to set up some permissions for CloudFront to access it. The alternative is to point it to the S3 website instead

    Use www.storyclub.co.uk.s3-website.eu-west-2.amazonaws.com, not www.storyclub.co.uk.s3.amazonws.com

  • Viewer Protocol Policy - Redirect HTTP to HTTPS

  • Object caching - customize this

    Set everything to 0 to disable caching (only if you want to!)

  • Alternate domain names (CNAMEs) - set this to www.storyclub.co.uk

  • SSL Certificate. Choose "Custom ssl cert" and then pick the right one

    Don't see your certificate? Sure you created one? Make sure it's in the N.Virginia region!

Create it!

This takes a few minutes

3 - DNS

Pretty straightfoward. In Route53 change the A record for www.storyclub.co.uk to point to randomnumbers23998237489237493.cloudfront.net instead of s3-website.region.amazonaws.com

Do not do the same for the storyclub.co.uk A record. Redirecting from a naked domain (storyclub.co.uk) to www is handled by S3. What happens in this case is

  1. User hits storyclub.co.uk, which is the Amazon S3 web server
  2. This sends the user a HTTP redirect, telling them to go to www.storyclub.co.uk instead
  3. User hits www.storyclub.co.uk, which is the CloudFront server

What about caching?

For the moment, caching is disabled. I need to be able to publish stories to the website and have then visible immediately.

Some notes

You can specify cache durations against S3 objects themselves. If there's nothing set then CloudFront defaults to 24 hours. This is a problem if you change a page: people might not see the new version for up to 24 hours.

Options

  • Alter the CloudFront behaviour to disable caching.

    Yay. Changes are immediately visible. This is nice and simple, but nothing is cached by CloudFront.

    This isn't a problem for www.storyclub.co.uk at the moment

  • Set cache control headers against S3 objects e.g. give things like CSS or JS a long cache duration, and use a shorter one for content that might change more frequently.

In the case of our website, perhaps we'll go with 5 minutes as the cache duration for brand new stories, because frequently we'll publish a story and then notice a typo. Bit of a bummer if you have to wait 24 hours to correct a typo.

Buy for old stories, we can set the cache duration to something far longer

(You can also explicitly remove items from the CloudFront cache, but this is a more expensive approach).