In this post, let’s see how to create an S3-CloudFront website with terraform module.

We assume you have an SSL certificate in AWS certificate manager in the issued state and also have access to DNS for pointing the site
With this code, you can create an s3 bucket and CloudFront distribution. Once the distribution is created you may add the CloudFront record in DNS. You will also need to add files in s3 and might need to create an invalidation with “/*” for quick results.

Here we have two directories in the root directory. the s3-CloudFront directory is the module code for creating s3 and CloudFront, whereas the env folder consists of calls to the modules. This env directory is not mandatory, but i would suggest this way so that we can separate parallel envs in folders.
So now let’s start with the s3-CloudFront directory. This directory consists of two files main.tf and variables.tf.
#creating s3 bucket | |
resource "aws_s3_bucket" "s3-bucket" { | |
bucket = "${var.environment}-${var.name}" | |
acl = "private" | |
tags = { | |
Name = "${var.environment}-${var.name}" | |
Environment = var.environment | |
} | |
} | |
# creating s3 bucket policy | |
data "aws_iam_policy_document" "s3-bucket" { | |
statement { | |
actions = ["s3:GetObject"] | |
resources = ["${aws_s3_bucket.s3-bucket.arn}/*"] | |
principals { | |
type = "AWS" | |
identifiers = [aws_cloudfront_origin_access_identity.s3-bucket.iam_arn] | |
} | |
} | |
statement { | |
actions = ["s3:ListBucket"] | |
resources = [aws_s3_bucket.s3-bucket.arn] | |
principals { | |
type = "AWS" | |
identifiers = [aws_cloudfront_origin_access_identity.s3-bucket.iam_arn] | |
} | |
} | |
} | |
#attaching bucket policy | |
resource "aws_s3_bucket_policy" "s3-bucket" { | |
bucket = aws_s3_bucket.s3-bucket.id | |
policy = data.aws_iam_policy_document.s3-bucket.json | |
} | |
#creating cloudfront access identity | |
resource "aws_cloudfront_origin_access_identity" "s3-bucket" { | |
comment = "origin identity for ${var.environment}-${var.name}" | |
} | |
#creating cloudfront distribution | |
resource "aws_cloudfront_distribution" "s3-bucket" { | |
origin { | |
domain_name = aws_s3_bucket.s3-bucket.bucket_regional_domain_name | |
origin_id = "${var.environment}-${var.name}" | |
s3_origin_config { | |
origin_access_identity = aws_cloudfront_origin_access_identity.s3-bucket.cloudfront_access_identity_path | |
} | |
} | |
enabled = true | |
is_ipv6_enabled = true | |
default_root_object = var.root_object | |
wait_for_deployment = false | |
aliases = [var.domain] | |
default_cache_behavior { | |
allowed_methods = ["GET", "HEAD"] | |
cached_methods = ["GET", "HEAD"] | |
target_origin_id = "${var.environment}-${var.name}" | |
forwarded_values { | |
query_string = false | |
cookies { | |
forward = "none" | |
} | |
} | |
min_ttl = 0 | |
default_ttl = 86400 | |
max_ttl = 31536000 | |
compress = true | |
viewer_protocol_policy = "redirect-to-https" | |
} | |
restrictions { | |
geo_restriction { | |
restriction_type = "none" | |
} | |
} | |
custom_error_response { | |
error_code = 404 | |
response_page_path = "/index.html" | |
response_code = 200 | |
} | |
tags = { | |
Environment = var.environment | |
} | |
viewer_certificate { | |
acm_certificate_arn = var.acm | |
#minimum_protocol_version = "TLSv1.2_2021" | |
ssl_support_method = "sni-only" | |
#cloudfront_default_certificate = true | |
} | |
} |
In this main.tf we create an S3 bucket and attach a bucket policy with GetObject access to CloudFront origin access identity. Then a CloudFront distribution is created with the ACM arn and in the domain provided by us. Now let’s see variables.tf
variable "environment" {} | |
variable "name" {} | |
variable "acm" {} | |
variable "domain" {} | |
variable "root_object" {} |
In variables.tf file we request 5 variables.
- variable “environment” {} : This variable stands for the Env of resource and is appended with s3 bucket name.
- variable “name” {} : This is name of the resources
- variable “acm” {} : arn of AWS Certificate manager is provided here. Make sure this certificate is in “issued” status
- variable “domain” {} : This will be the custom domain name of our distribution.
- variable “root_object” {} : usually index.html
Now let’s see what’s in the env/prod directory. Here we have the parent module which we call the child module.
##S3-Cloudfront | |
module "sampleapp-prod-frontend-s3cloud" { | |
source = "../../s3-cloudfront" | |
environment = "sampleweb-prod" | |
name = "frontend" | |
root_object = "index.html" | |
acm = "arn:aws:acm:us-east-1:123456789101:certificate/4cb08723-6052-4853-8d1f-5674ac80d092" | |
domain = "app.example.com" | |
} |
In this main.tf we provide variable values and the location of the module directory.
Now let’s check out the main.tf and provider.tf in the root directory.
module "prod"{ | |
source = "./env/prod" | |
} |
provider "aws"{ | |
profile = "profilename" | |
region = "us-east-1" | |
} |
so that’s it for creating an s3 bucket and distribution. In case we are planning to create a new env you may create a new folder in the env directory and add main.tf with appropriate changes, also don’t forget to add this module in root main.tf.
Once resources are created you can add site files in the s3 bucket and create an invalidation with “/*” for faster clearing of cache.