Static Website Hosting on S3 using Terraform.

Static Website Hosting on S3 using Terraform.

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:

  1. Passing them as input to other modules or configurations.

  2. Accessing them in scripts for further automation or reporting.

  3. 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.

  1. 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.

  1. 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]

cloudfront.tf :

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 :)