Host Static website using AWS CDK for Terraform and CloudFront: Part 2

thakkaryash94

Yash Thakkar

Posted on August 7, 2020

Host Static website using AWS CDK for Terraform and CloudFront: Part 2

In part 1, we saw how we can host our website using S3. In this part, we will see how we can configure AWS CloudFront to serve our S3 bucket objects as website. In case, if you have not checked out the Part 1, please read this first.

Let's setup CloudFront distribution using AWS CDK of Terraform. We need to create CloudFront Origin Access Identity(OAI), which we will use for CloudFront and S3 bucket policy.

import { CloudfrontOriginAccessIdentity } from './.gen/providers/aws';

/*
 * Create am Origin Access Identity
 * Doc link: https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-access-to-amazon-s3/
 * Tutorial link: https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-access-to-amazon-s3/
 */
const cloudfrontOriginAccessIdentity = new CloudfrontOriginAccessIdentity(this, 'aws_cloudfront_origin_access_identity', {
  comment: 's3-cloudfront-cdk-example'
})
Enter fullscreen mode Exit fullscreen mode

Now, we need to set few required parameters for the CloudFront configuration.

  • dependsOn: Bucket is required to setup CloudFront.
  • defaultRootObject: index.html is our default file that we need to serve.
  • customErrorResponse: We can setup custom rules/response for errors like 400, 404, 500, 501 etc.
  • origin:
    • originId: unique id (should be same as targetOriginId)
    • domainName: S3 bucket as domain (eg. thakkaryash94-cdk-dev.s3.amazonaws.com)
  • defaultCacheBehavior:
    • targetOriginId: unique id (should be same as originId)
  • restrictions: We want our website be to accessible from everywhere, so set it to none.
  • viewerCertificate: We can use CloudFront default certificate and can also add custom ACM certificate, IAM certificate etc.
import { CloudfrontDistribution } from './.gen/providers/aws';

const originId = `S3-${BUCKET_NAME}`;

const cloudFrontDistribution = new CloudfrontDistribution(this, `aws_cloudfront_${BUCKET_NAME}`, {
  enabled: true,
  dependsOn: [bucket],
  defaultRootObject: 'index.html',
  customErrorResponse: [{
    errorCode: 404,
    responseCode: 200,
    responsePagePath: '/index.html'
  }],
  origin: [{
    originId: originId,
    domainName: bucket.bucketDomainName,
    s3OriginConfig: [{
      originAccessIdentity: cloudfrontOriginAccessIdentity.cloudfrontAccessIdentityPath
    }]
  }],
  defaultCacheBehavior: [{
    allowedMethods: ['GET', 'HEAD'],
    cachedMethods: ['GET', 'HEAD'],
    forwardedValues: [{
      cookies: [{ forward: 'none' }],
      queryString: false
    }],
    targetOriginId: originId,
    viewerProtocolPolicy: 'allow-all'
  }],
  restrictions: [{
    geoRestriction: [{
      restrictionType: 'none'
    }]
  }],
  viewerCertificate: [{
    cloudfrontDefaultCertificate: true
  }],
});
Enter fullscreen mode Exit fullscreen mode

Previously, our bucket was public, it means anyone can access bucket objects using bucket website URL. Now, we have configured CloudFront to serve our website, so it's time to block that access. With this, our website will be only accessible by CloudFront URL only. No-one will be able to access bucket objects using S3 website URL.

bucket.acl = 'private'            // Set bucket ACL as private
bucket.website = []               // Disable website hosting feature
bucket.policy = `{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${cloudfrontOriginAccessIdentity.id}"
      },
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::${BUCKET_NAME}/*"
      ]
    }
  ]
}`
Enter fullscreen mode Exit fullscreen mode

Last, we will print the CloudFront url, which will serve our s3 objects as a website.

// Output the cloudfront url to access the website
new TerraformOutput(this, 'cloudfront_website_endpoint', {
  description: 'CloudFront URL',
  value: `https://${cloudFrontDistribution.domainName}`
});
Enter fullscreen mode Exit fullscreen mode

Now, we follow the same process to deploy the changes as per the Part 1. After successfull deployment, CloudFront public URL will be printed on the console and we will be able to access our website with default https certificate.

So this is how, we can setup CloudFront with AWS S3 using AWS CDK for Terraform.

GitHub logo thakkaryash94 / terraform-cdk-react-example

Host react website using terraform CDK on AWS S3

Host Static website using AWS CDK for Terraform

This repo contains the code for DEV.to blog

Links:

💖 💪 🙅 🚩
thakkaryash94
Yash Thakkar

Posted on August 7, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related