Deploy static site with Terraform module in AWS S3

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
}
}
view raw main.tf hosted with ❤ by GitHub

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" {}
view raw variables.tf hosted with ❤ by GitHub

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"
}
view raw main.tf hosted with ❤ by GitHub

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"
}
view raw main.tf hosted with ❤ by GitHub
provider "aws"{
profile = "profilename"
region = "us-east-1"
}
view raw provider.tf hosted with ❤ by GitHub

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: