Kristian Glass - Do I Smell Burning?

Pointing AWS CloudFront at an S3 website with CloudFormation

You have a static website in an S3 bucket. You want to put CloudFront in front of that bucket site, for caching, SSL with a custom domain, etc. You want to use CloudFormation because Infrastructure as Code for the win, and artisanally hand-crafted systems for the lose.

In short, this is the magic you want in your CloudFormation template, with thanks to Eric Hammond and Ryan Brown:

SiteBucket:
  Type: "AWS::S3::Bucket"
  # Snip
Mappings:
  RegionToS3DomainSuffix:
    "us-east-1":
      suffix: "s3-website-us-east-1.amazonaws.com"
    "eu-central-1":
      suffix: "s3-website.eu-central-1.amazonaws.com"
    # I've not investigated other regions...
CF:
  Type: "AWS::CloudFront::Distribution"
  Properties:
    DistributionConfig:
      Origins:
        -
          DomainName:
            "Fn::Join":
              - "."
              -
                - !Ref SiteBucket
                - !FindInMap [RegionToS3DomainSuffix, !Ref "AWS::Region", suffix]

Yes that’s an ugly hand-crafted Join. Yes that’s an ugly hand-crafted Mapping to account for different regions having different bucket website URL conventions. However, it works.

In an ideal world, AWS::S3::Buckets would have a WebsiteDomain attribute so you could !GetAttr SiteBucket.WebsiteDomain. Alas at time of writing (October 2016) they don’t.

AWS::S3::Bucket.WebsiteURL exists but it returns a URL, with leading http:// and trailing /. Stripping these within a CloudFormation template is beyond me.

As far as I can tell, icky region-specific substitutions are where it’s at for now!

Note: Originally I’d proposed a range of hardcoded Fn::Subs that only worked for a subset of regions. Thanks to Eric Hammond for pointing out how it could be improved with Mappings

Comments