Today we are going to host a static website using Amazon S3 and Will deploy the same website on CloudFront as an Origin Access Identity which is a global content delivery network through, we can replicate the applications in edge locations using Terraform.
What is Terraform?
Terraform is an open-source infrastructure as code (IaC) tool developed by HashiCorp. It's used for managing and provisioning infrastructure resources in a declarative and automated way.
Here's what Terraform is used for:
1)Infrastructure Automation
2)Declarative Syntax
3)Multi-Cloud and Hybrid Cloud Support
4)Immutable Infrastructure
5)Plan and Apply Workflow
6)Modularity and Reusability
7)Infrastructure Scaling and more.
Overall, terraform simplifies the process of managing infrastructure by providing a standardized, consistent, and automated approach to provisioning and maintaining resources. It helps organizations achieve greater efficiency, agility, and reliability in their infrastructure management practices.
Installation of Terraform: Install | Terraform | HashiCorp Developer (refer to this link and download the terraform)
Terraform Commands
1)Terraform init
: Initializes a new or existing Terraform working directory by downloading and installing provider plugins.
2)Terraform plan:
Creates an execution plan showing what changes Terraform will make to the infrastructure based on your configuration. It does not actually make any changes.
3)Terraform apply
: Applies the changes proposed in the execution plan. It creates, updates, or deletes resources to match the desired state specified in your configuration.
4)Terraform destroy
: Destroys all the resources managed by your Terraform configuration. Use with caution, as it will delete infrastructure.
5)Terraform validate
: Validates the syntax of the configuration files and checks for basic errors without creating or modifying resources.
6)Terraform fmt
:Rewrites configuration files to a consistent format, making it easier to read and maintain the code.
7)Terraform output
: Displays the values of output variables defined in your configuration.
8)Terraform taint
: Marks a resource as tainted, causing it to be destroyed and recreated on the next Terraform apply
.
What are Variables?
Variables are used to parameterize your configurations and make them more flexible and reusable. They allow you to define values that can be customized when you use a module or configuration.
Input Variables: Input variables are used to accept values from users or configurations and provide dynamic values to your Terraform modules or configurations. They are defined within the variables.tf
file using the variable block.
Type: Variables in Terraform can have different data types, such as string, number, list, map, etc. You can specify the expected type using the type
argument in the variable definition.
Default Values: You can provide default values for input variables, which will be used if a value is not explicitly provided during the Terraform run.
Sensitive Variables: If a variable contains sensitive information like passwords, you can mark it as sensitive to prevent its value from being displayed in the console output during terraform apply.
sensitive = true
variable "bucket_name" {
description = "Name of the S3 Bucket"
type = string
}
variable "tags" {
description = "Tags to set on buckets"
type = map(string)
}
variable "Region_aws" {
description = "Name your aws region "
type = string
default = "us-east-1" // You can remove this give your desired region during terraform.
}
variable "access_key" {
description = "Pass your Access Key"
type = string
default = "place your access key value here"
}
variable "secret_key" {
description = "Pass your Secret Key"
type = string
default = "place your secret key value here"
}
What are Outputs?
Outputs are a way to expose specific values from your Terraform configuration, making them accessible for other configurations, scripts, or users.
Output values are defined using the output block within the outputs.tf
file of your Terraform configuration.
Using Output Values: Output values can be used in various ways, such as:
Passing them as input to other modules or configurations.
Accessing them in scripts for further automation or reporting.
Displaying them to users after the terraform apply command to provide information about the created resources.
Like variables, outputs can also be marked as sensitive if they contain confidential information.
sensitive = true
output "arn" {
description = "ARN of the Bucket"
value = aws_s3_bucket.s3bucket1.arn
}
output "ID" {
description = "Id of the Bucket"
value = aws_s3_bucket.s3bucket1.id
}
output "domain" {
description = "domain of the bucket"
value = aws_s3_bucket.s3bucket1.bucket_regional_domain_name
}
output "cdnarn" {
description = "Cloudfront arn"
value = aws_cloudfront_origin_access_identity.s3cdn.iam_arn
}
Here is the below terraform is related to S3 Bucket Static hosting.
Provider
A provider in Terraform is responsible for interacting with a specific infrastructure platform or service, such as a cloud provider (e.g., AWS, Azure, Google Cloud), a version control system (e.g., GitHub), a DNS provider, a database service, and more.
Resources
Resources are the building blocks of your infrastructure configurations in Terraform. They represent the various components you want to create and manage, such as virtual machines, storage buckets, databases, networks, and more.
provider "aws" {
region = var.Region_aws
access_key = var.access_key
secret_key = var.secret_key
}
// this block of code is used to create a s3 bucket and tag
resource "aws_s3_bucket" "s3bucket1" {
bucket = var.bucket_name
tags = var.tags
force_destroy = true // makes bucket deleted and we dont need to make the bucket empty manually
}
// to enable the public access
resource "aws_s3_bucket_public_access_block" "publicaccessenable" {
bucket = aws_s3_bucket.s3bucket1.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
//this makes enable bucket versioning
resource "aws_s3_bucket_versioning" "versioning_enabling" {
bucket = aws_s3_bucket.s3bucket1.id
versioning_configuration {
status = "Enabled"
}
}
// static web hosting
resource "aws_s3_bucket_website_configuration" "webconfig" {
bucket = aws_s3_bucket.s3bucket1.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
// this a bucket policy used to access the s3 bucket objects
resource "aws_s3_bucket_policy" "public_bucketpolicy" {
bucket = aws_s3_bucket.s3bucket1.id
policy = data.aws_iam_policy_document.public_bucketpolicy.json
}
data "aws_iam_policy_document" "public_bucketpolicy" {
statement {
principals {
type = "AWS"
identifiers = ["*"]
}
actions = [
"s3:GetObject",
]
resources = [
"arn:aws:s3:::vishnubucket2024/*",
]
}
}
Steps to follow for Static Web Hosting on S3 and CloudFront using terraform:
1)Now we will run terraform commands to get started with terraform fmt
makes sure format is good.
2)Next step is to validate our configuration with terraform validate
3)Now we need to initialize Terraform working directory by downloading and installing provider plugins using terraform init
4)Next, we need to run terraform plan
command. It will create an execution plan based on our configuration.
5)Next, by using Terraform apply
command it will creates the infrastructure in provider with all necessary resources mentioned in the configuration. We have configured a Outputs.tf
file so it is showing configured output values in the console.
- We can see a S3 Bucket has been created in aws . now we need to upload objects like index.html, tyle.css, images related the site you're hosting.
- After uploading files, under properties you can find the Static Website hosting and you can get the website endpoint.
Here we go. we are successfully hosted a static website on S3.
Now, we will deploy same website on CloudFront before that, Amazon CloudFront is a content delivery network (CDN) service provided by Amazon Web Services (AWS). It helps to deliver static and dynamic content, such as web pages, images, videos, and audio files, to users from the nearest edge location, reducing latency and improving load times.
We need to create another terraform configuration as below for CloudFront and we need to change the s3 bucket policy for CloudFront to access the bucket objects like below and comment out static website hosting related part in s3bucket.tf file:
identifiers = [aws_cloudfront_origin_access_identity.s3cdn.iam_arn]
locals {
s3_origin_id = "myS3Origin"
}
// to create the cloudfront origin access identity for the s3 bucket
resource "aws_cloudfront_origin_access_identity" "s3cdn" {
provider = aws
comment = "cf for s3 bucket"
}
resource "aws_cloudfront_distribution" "myCDN" {
provider = aws
origin {
domain_name = aws_s3_bucket.s3bucket1.bucket_domain_name
origin_id = local.s3_origin_id
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.s3cdn.cloudfront_access_identity_path
}
}
enabled = true
default_root_object = "index.html"
//This is related to cache behavior
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 = "redirect-to-https"
min_ttl = 0
default_ttl = 3000
max_ttl = 86400
}
// it restricts the users to access the website except USA and India
restrictions {
geo_restriction {
restriction_type = "whitelist"
locations = ["US", "IN"]
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
After the same set of terraform commands the CloudFront is got created as below
d3us9jfmn6e6o5.cloudfront.net , Distribution domain link through this you see the site. We can also Route to better DNS name using CNAME in Route53 and mention DNS name as like this in cloudfront.tf file.
alias=["mylogin.example.com"]
Now we need to destroy the resources by using terraform destroy
command:
Successfully all resources are destroyed.
This is how we can Host a static website on s3 and CloudFront using terraform. Happy learning :)