Software Developer
If you want to skip all of the fun the repo with the code we are using is located here. Also, before you get started here go check out my article on creating an S3 website bucket module. This article will be building on the groundwork set there and will assume you have an S3 bucket module.
For this article, I am going to assume that you already have an S3 website created and just want to get it deployed to Cloudfront using Terraform. If that happens to not be the case here is the code we are working with.
Main. tf
resource "aws_s3_bucket" "prod_website" {
bucket_prefix = var.bucket_prefix
acl = "public-read" website {
index_document = "index.html"
error_document = "error.html"
}
}
resource "aws_s3_bucket_policy" "prod_website" {
bucket = aws_s3_bucket.prod_website.id policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::${aws_s3_bucket.prod_website.id}/*"
]
}
]
}
POLICY
}
Variables.tf
variable "bucket_prefix" {
type = string
description = "Name of the s3 bucket to be created."
}
variable "region" {
type = string
default = "us-east-1"
description = "Name of the s3 bucket to be created."
}
Outputs.tf
output "s3_bucket_id" {
value = aws_s3_bucket.prod_website.id
}
Use these files as the basis for your code. We will just be updating them with our Cloudfront code.
Cloudfront Code in main. tf
So the code we are going to be adding to our main. tf file is this:
resource "aws_cloudfront_distribution" "s3_distribution" {
origin {
domain_name = "${aws_s3_bucket.prod_website.bucket_regional_domain_name}"
origin_id = "${local.s3_origin_id}"
# s3_origin_config {
# origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
# }
}
enabled = true
is_ipv6_enabled = true
comment = "Some comment"
default_root_object = "index.html"
# logging_config {
# include_cookies = false
# bucket = "mylogs.s3.amazonaws.com"
# prefix = "myprefix"
# }
#aliases = []
default_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "${local.s3_origin_id}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
# Cache behavior with precedence 0
ordered_cache_behavior {
path_pattern = "/content/immutable/*"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD", "OPTIONS"]
target_origin_id = "${local.s3_origin_id}"
forwarded_values {
query_string = false
headers = ["Origin"]
cookies {
forward = "none"
}
}
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000
compress = true
viewer_protocol_policy = "redirect-to-https"
}
# Cache behavior with precedence 1
ordered_cache_behavior {
path_pattern = "/content/*"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "${local.s3_origin_id}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
compress = true
viewer_protocol_policy = "redirect-to-https"
}
price_class = "PriceClass_200"
restrictions {
geo_restriction {
restriction_type = "whitelist"
locations = ["US", "CA", "GB", "DE"]
}
}
tags = {
Environment = "production"
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
I am just going to break down a few specific pieces of this. First, let’s look at the domain_name argument.
resource "aws_cloudfront_distribution" "s3_distribution" {
origin {
domain_name = "${aws_s3_bucket.prod_website.bucket_regional_domain_name}"
origin_id = "${local.s3_origin_id}"
We want to set this argument to
aws_s3_bucket.prod_website.bucket_regional_domain_name because that is the resource addressing that will be used to pull the domain name information.
Next is the origin_id argument.
resource "aws_cloudfront_distribution" "s3_distribution" {
origin {
domain_name = "${aws_s3_bucket.prod_website.bucket_regional_domain_name}"
origin_id = "${local.s3_origin_id}"
I do not have this in use for this example, but if you want to set an origin_id you can just use the commented out expression:
# s3_origin_config {
# origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
# }
}
For default_root_object we have it set to index.html since that is a good default.
enabled = true
is_ipv6_enabled = true
comment = "Some comment"
default_root_object = "index.html"
All of this code can just be added to the main.tf file that contains our bucket and bucket policy.
Cloudfront Code in variables. tf
There is none!
<div style=”width:100%;height:0;padding-bottom:67%;position:relative;”><iframe src=”https://giphy.com/embed/F9hQLAVhWnL56" width=”100%” height=”100%” style=”position:absolute” frameBorder=”0" class=”giphy-embed” allowFullScreen></iframe></div><p><a href=”https://giphy.com/gifs/F9hQLAVhWnL56">via GIPHY</a></p>
Cloudfront Code in outputs.tf
We also want to add this to the outputs.tf file.
output "s3_bucket_domain_name" {
value = aws_s3_bucket.prod_website.bucket_domain_name
}
That way our parent module can get the bucket domain name of our child module.
If you looked at my repo you may also notice a few other outputs. These you will only want to use in specific scenarios, but more on that in future articles!
Usage
You should now have everything you need. After configuring your AWS provider in your code the below example will get your website created.
module prod_website {
source = "YOUR SOURCE URL"
bucket_prefix = "SOME BUCKET NAME"
}