How to create a website using S3 + Certificate Manager + Cloud Front with CDK ?


Before start we need a few things installed on our computer.

1) npm
2) NodeJs + TypeScript(2.7 or later)
3) CDK

After that we have to set up your aws credentials, to achieve that you can follow this link

The last one, you should have created a hosted zone in AWS and delegate your domain.

Well, we can start!!

Configure SSL certificate

const hostedZone = HostedZone.fromLookup(this,"myZone", {
    domainName: ""

const certificate = new acm.Certificate(this, `myCertificate`, {
      domainName: "",
      subjectAlternativeNames: [""],
      validation: acm.CertificateValidation.fromDns(hostedZone),

On the first part we got the hosted zone related to your domain.
After that we created the SSL certificate using Certificate Manager. Adding the key validation into the CM, AWS automatically add the necessary records to validate your domain.

Set up bucket

const bucket = new Bucket(this, `myBucket`, {
      encryption: BucketEncryption.S3_MANAGED,
      bucketName: `your-bucket-name`,
      cors: [
          allowedMethods: [HttpMethods.GET, HttpMethods.HEAD],
          allowedOrigins: ["*"],
          allowedHeaders: ["*"],

In this way we create the bucket. It's recommended to use the domain's name as bucket's name and use a prefix to difference the environments.

Set up policy and CDNOAI

In this part, I am going to explain step by step, because It could be a bit confuse.

const CDNOAI = new CfnCloudFrontOriginAccessIdentity(
      this, "myCDNOAI", {
        cloudFrontOriginAccessIdentityConfig: {
          comment: "S3 OAI",

What is cloud front origin access identity ?

An Origin Access Identity (OAI) is used for sharing private content via CloudFront. The OAI is a virtual user identity that will be used to give your CF distribution permission to fetch a private object from your origin server (e.g. S3 bucket).

const policy = new iam.PolicyStatement({
      actions: ["s3:Get*"],
      effect: Effect.ALLOW,
      resources: [bucket.bucketArn, bucket.arnForObjects("*")],

We created a policy to allow get object on the whole bucket.


We add our CDNOAI to our policy.

const bucketPolicy = new BucketPolicy(this, `myBucketPolicy`, { 


The last step of this section is create a bucket policy and attach to it our policy.

Set up Cloud front

const cloudFront = new cloudfront.Distribution(
        defaultBehavior: {
          origin: new origins.S3Origin(bucket),
          allowedMethods: AllowedMethods.ALLOW_GET_HEAD,
          viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        defaultRootObject: "index.html",
        domainNames: [""],
        enabled: true,
        errorResponses: [
            ttl: Duration.days(1),
            httpStatus: 404,
            responseHttpStatus: 200,
            responsePagePath: "/index.html",
            ttl: Duration.days(1),
            httpStatus: 403,
            responseHttpStatus: 200,
            responsePagePath: "/index.html",

This is a basic cloudfront configuration.

I want to highlight the certificate variable. It is the same certificate that we previously created.

Create A record

new ARecord(this, `myARecord`, {
      zone: hostedZone,
      ttl: Duration.minutes(5),
      target: RecordTarget.fromAlias(new targets.CloudFrontTarget(cloudFront)),
      recordName: "",

In this part we are going to create an A record within our hosted zone, and reference it with our cloud front.


This is my github, and here you are going to find a full complete example using CDK to create and deploy powerfull webapps!!