CloudFront with SSL from S3

von

Recently I updated “Time & Bill” and messed it up. It was exhausting two days, but looking back, I learned a lot.

I have moved my app from a classic EC2 instance to Elastic Beanstalk and at the same time, I separated my “content pages” from the app. I wanted to update my content more often, and buried in my app this wasn’t an easy task.

My old EC2 instance was suddenly breaking up, and so I had to put the switch a bit earlier than thought.

I soon realized, my customers were just pressing on a bookmark to reach my app. Many of them used https:// (to my surprise) and they weren’t able to reach my website as S3 only supports http:// by default. Also my mobile app was breaking because of the domain shift: rewriting didn’t help, as I forgot the mobile app is using https:// by default.

CloudFront came as the solution. CloudFront is a CDN service provided by Amazon WebServices. It distributes your content to so-called edge locations, were it’s distributed to more or less regional consumers. For example, my Germany based S3 files would be duplicated to somewhere in Australia. If somebody from down-under accesses my website, they would be served directly from the Australian edge location. CDN speed up your website and in some cases could even lower you costs. S3 access is more expensive than CloudFront access.

Custom domains are supported using CNAME and custom SSL certificates are as well. However, it only makes sense if you accept the restriction only SNI enabled browser can access your content. Otherwise, you’d have to pay $600 for a dedicated IP and this is ways to much for many companies.

I headed over to Gandi.net and was able to get a certificate with 1-year validity for under €15. My recommendation is to get that first as it takes it’s while to retrieve it. You need to validate and using e-mail validation took me only 30 minutes, but DNS validation would take much longer. I did that once, and it took me several hours.

Next step is to bring the certificate to your AWS account. I recommend you to create a new special user which has the right “IAM Full Access”. Open your shell and cd to your folder with the certificate.

Then first configure the AWS CLI tools using:

aws configure

You’ll need enter your access key and secret. If you are lazy, like me, you can also do it like:

vi ~/.aws/credentials

[cert-user]
aws_access_key_id = xxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxx

The “cert-user” would be available as profile then.

The next step would be to get Gandi’s intermediate certificate:

curl -O 'https://www.gandi.net/static/CAs/GandiStandardSSLCA.pem'

Attention: with SHA-2 certificates (which you should prefer) you should download

https://www.gandi.net/static/CAs/GandiStandardSSLCA2.pem

The PEM includes everything you need. You can also find a direct link in your Gandi-Backend.

Afterwards you can upload the certificate already using:

aws iam upload-server-certificate \
   --server-certificate-name my-name-as-i-want-it \
   --certificate-body file://certificate-from-gandi.crt \
   --private-key file://my-private-key.key  \
   --certificate-chain file://GandiStandardSSLCA2.pem \
   --path /cloudfront/another-name-of-mine/ \
   --profile cert-user

Please note, the order of the parameters might be important. The certificate name is only here to identify your certificate in the AWS web interface. Chose one you like. Certificate-Body is the certificate you got from Gandi. The private key is the key you created when creating the CSR.

If you leave out the certificate-chain, the upload will work. However the web-interface would deny using it.

The path is something that needs to start with /cloudfront. I am not perfectly sure how it is used from AWS, but I guess it just the path where you store the object. Finally, I used the profile from .aws/credentials, which is cert-user.

Your response should look like:

{
    "ServerCertificateMetadata": {
        "ServerCertificateId": "xxxxxxxx",
        "ServerCertificateName": "domain.com",
        "Expiration": "2016-05-04T23:59:59Z",
        "Path": "/cloudfront/another-name-of-mine/",
        "Arn": "arn:aws:iam::xxxx:server-certificate/cloudfront/another-name-of-mine/domain.com",
        "UploadDate": "2015-04-14T17:02:49.437Z"
    }
}

If you have messed something up and you would like to remove that certificate again, then you can use:

aws iam delete-server-certificate --server-certificate-name my-name-as-i-want-it --profile certificates

Now we got it up and running.

It’s time to move on to the CloudFront website and create a new distribution. In our case, we would create a web distribution.

Clicking the “origin domain name” would let you chose your S3 website. The origin is - as you maybe assume - where your content comes from. Leave “origin path” empty, as it would manipulate your path which we most likely don’t want. Origin-ID is more interesting again.

If you would just create this bucket and have the option “root object” set to index.html, the domain mydomain.com would resolve this file:

mydomain.com/index.html

However, mydomain.com/en/ would not work, as the sub folders index.html would not be seen as root object. CloudFront works different to S3 in this case. If you don’t work to rework all of your URLs, you can use a “custom origin”. Doing so helped me a lot.

Instead of choosing the suggested “mydomain.com.s3.amazon.com” you should check the properties of your bucket. There is the original bucket name that looks like “mydomain.com.s3-website-eu-west-1.amazonaws.com”. Add this URL as your origin path and CloudFront would take it as custom source. S3 is then treated like a standard web-server and not just as part of the AWS eco system. S3 can deal with index.html files in sub-folders and so you would end up getting the right file as the redirect logic would be available.

The rest of the entries are self-explanatory. However, make sure you chose your custom SSL certificate and put your domain name to CNAME! Do the latter one including the www prefix. Otherwise you might run into trouble. When you are happy with your distribution, hit “Create Distribution” and wait quite a bunch of time. Even for smaller websites it can take an hour to distribute your content to all edges.

I recommend you to test your website using the provided CloudFront domain. If you are happy again, you can move on to your DNS provider and finally switch your www. domain as CNAME to your CloudFront domain. That’s it.

Tags: #CloudFront #AWS #S3 #SSL

Newsletter

ABMELDEN