Skip to content

CDK stack that deploys a website hosted in an S3 bucket, exposed through a CloudFront distribution and routed through Cloudflare.

Notifications You must be signed in to change notification settings

dropkitchen/cdk-cloudflare-s3-website

Repository files navigation

Cloudflare AWS S3 Website CDK stack

CloudflareS3Website is a very opinionated AWS CDK stack that deploys a website to AWS using Cloudflare as the DNS provider. It does the following for you:

  • Creates an S3 bucket to deploy the files of your choice.
  • Creates a CloudFront distribution that serves the files in the bucket, with access limited to Cloudflare only.
  • Creates the necessary ACM certificates for the domain configuration.
  • Creates a DNS record in Cloudflare that points to the above distribution.

All this by applying best practices in resource configuration and cost saving measures.

Prerequisites

  • An AWS account.
  • A Cloudflare account.

Limitations

The entire setup and deployment of resources must be done in us-east-1. The reason is that the ACM certificates used by CloudFront distributions must be hosted in this region.

Setup

Cloudflare

The first part is to generate an API token with the necessary permissions to edit the DNS of a zone. This step only needs to be completed once.

In order to do this visit the API tokens section of the user profile and create an API token that has the DNS:Edit permission on any zone or the zone in particular where the website is to be created. Copy and store the API token value for later.

AWS

The steps defined in this section only need to be performed once per AWS account.

  1. Create an IAM execution role that can be assumed by CloudFormation. The following policy must be added to the “Trusted entities” section, replacing <AWS_ACCOUNT_ID> with the ID of the account being used:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "resources.cloudformation.amazonaws.com"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "<AWS_ACCOUNT_ID>"
                },
                "StringLike": {
                    "aws:SourceArn": "arn:aws:cloudformation:us-east-1:<AWS_ACCOUNT_ID>:type/resource/Cloudflare-Dns-Record/*"
                }
            }
        }
    ]
}
  1. Navigate to CloudFormation. Select "Public extensions" from the left hand pane and filter "Publisher" by "Third Party". Add Cloudflare::Dns::Record to the "Extensions" search bar.
  2. Select the extension in the result and click on the "Activate" button. Specify the "Execution role ARN" from the IAM execution role created in the first step. Use the following extension configuration, replacing <CLOUDFLARE_API_TOKEN> with the API token generated in the Cloudflare setup:
{
    "CloudflareAccess":{
        "Url": "https://api.cloudflare.com/client/v4",
        "ApiKey": "<CLOUDFLARE_API_TOKEN>"
    }
}

And you are good to go!

Usage

An example will be used to explain the usage. Suppose we have an index.html file that we want to deploy and we have obtained the zone ID from Cloudflare. In the file where the stacks are defined, usually app.py, we would define the following:

from aws_cdk import App
from aws_cdk.aws_s3_deployment import Source

from cdk_cloudflare_s3_website import CloudflareS3Website

app = App()

CloudflareS3Website(
    app,
    construct_id="CloudflareS3WebsiteStack",
    default_root_object="index.html",
    cloudflare_zone_id="<CLOUDFLARE_ZONE_ID>",
    domain_name="<DOMAIN_NAME>",
    sources=[Source.asset("index.html")],
)

app.synth()

The CloudflareS3Website class takes the usual arguments of a CDK stack in addition to the following specific ones:

  • default_root_object: The default root object for the S3 website. This is the object that will be served when the user visits the root URL of the website.
  • cloudflare_zone_id: The ID of the Cloudflare zone where the website will be hosted.
  • domain_name: The domain name of the website.
  • sources: A list of aws_cdk.aws_s3_deployment.Source objects that define the files to be deployed to the S3 website.

The sources parameter can be used to deploy multiple files to the S3 website. For example, if we have a data directory with multiple HTML files, we can deploy them all by using the following:

sources=[Source.asset((Path.cwd() / "data").as_posix())],

This will deploy all the files in the data directory to the S3 website.

Deployment

To deploy the stack, run the following command:

cdk deploy

This will deploy the CloudFormation stack and create the necessary resources to host the S3 website on Cloudflare.

Cleanup

To delete the CloudFormation stack, run the following command:

cdk destroy

This will delete the CloudFormation stack and all the resources associated with it.

FAQ

Why CloudflareS3Website is a Stack instead of a Construct?

There is no other way to guarantee with certainty that the region to be deployed to is us-east-1. A Construct has no knowledge of its region unless credentials are used in the synthesis, whereas a Stack has an env parameter that allows the deployment to be limited.

About

CDK stack that deploys a website hosted in an S3 bucket, exposed through a CloudFront distribution and routed through Cloudflare.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages