Hosting Online Chmod Calculator on S3 Bucket
Tags: linux, chmod, webdev, aws
Published: 2024-01-09 17:57:53

## Hello Readers👋,

In this blog, we're going to embark on a journey into the realm of DevOps and Web Development. I'm excited to share a recent project of mine – a simple yet powerful combination of hosting a static website on an Amazon S3 bucket along with the added convenience of an online chmod calculator. 

##  Overview
Picture this: As a Linux Administrator, assigning POSIX permissions on files and directories is a common task, It is highly recommended to use octal notations for changing permissions. To address this, I decided to create an online chmod calculator seamlessly hosted as a static website on S3. This blog aims to simplify DevOps tasks and make web development more streamlined.

Building a well-organized static website is crucial for a smooth user experience. I'll share insights into the structure of the website, including tips on directory organization and file structure. After all, a tidy project makes for a happy developer.

So here's the idea, We are going to automate the process of hosting chmod calculator using Terraform and Terraform cloud.

### Prerequisites

Before we start, ensure you have the following prerequisites in place:

1. Terraform Installation: Make sure Terraform is installed on your machine. You can download it from the official Terraform website.
2. AWS Account: You'll need an AWS account to create an S3 bucket for hosting your static website. Obtain your AWS Access Key and Secret Access Key.
3. Terraform Cloud Account: Sign up for a Terraform Cloud account if you don't have one. This will be our platform for managing infrastructure.

I have already created Terraform Cloud workspace and exported credentials i.e., AWS Access Key and Secret Access Key as environment variables in Terraform Cloud Workspace.

![Terraform Workspace](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fwyaxp9fv5y5y9k4th5q.png)

### Terraform Configuration

Now, let's create the Terraform configuration files to define the infrastructure. I will be creating a terraform module to make this happen.

#### Child Module Structure:

```bash 
modules
│   └── s3_static_website
│       ├── index.html
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
```



`main.tf`

This is a Terraform configuration file. Terraform is an infrastructure-as-code (IaC) tool that allows you to define and provision infrastructure in a declarative manner. In main.tf, you specify the AWS resources you want to create or manage.
```hcl
#create s3 bucket
resource "aws_s3_bucket" "s3_bucket" {
  bucket = var.bucket_name
}

resource "aws_s3_bucket_public_access_block" "public_access_block" {
  bucket = aws_s3_bucket.s3_bucket.id

  block_public_acls       = var.block_public_acls
  block_public_policy     = var.block_public_policy
  ignore_public_acls      = var.ignore_public_acls
  restrict_public_buckets = var.restrict_public_buckets
}

resource "aws_s3_bucket_ownership_controls" "bucket_ownership_controls" {
  bucket = aws_s3_bucket.s3_bucket.id

  rule {
    object_ownership = var.object_ownership
  }
}

resource "aws_s3_bucket_acl" "acl" {
  bucket = aws_s3_bucket.s3_bucket.id
  acl    = var.acl
  depends_on = [
    aws_s3_bucket_ownership_controls.bucket_ownership_controls,
    aws_s3_bucket_public_access_block.public_access_block
  ]
}

resource "aws_s3_object" "index_file" {
  bucket       = aws_s3_bucket.s3_bucket.id
  key          = "index.html"
  source       = "index.html"
  acl          = var.acl
  content_type = var.content_type
  depends_on   = [aws_s3_bucket_acl.acl]
}

resource "aws_s3_bucket_website_configuration" "static_website" {
  bucket = aws_s3_bucket.s3_bucket.id
  index_document {
    suffix = "index.html"
  }
  depends_on = [ aws_s3_bucket_acl.acl ]
}

```

This Terraform script creates an Amazon S3 bucket and configures it to host a static website. The aws_s3_bucket resource defines the bucket with a user-specified name. Security measures are implemented using the aws_s3_bucket_public_access_block resource to block public access based on specified parameters. Object ownership controls are established through the aws_s3_bucket_ownership_controls resource, ensuring governance over data ownership within the bucket. Access Control Lists (ACLs) are set up using the aws_s3_bucket_acl resource to manage who can access objects within the bucket. An HTML file is uploaded to the bucket using the aws_s3_object resource, specifying ACL and content type. Finally, the bucket is configured for website hosting with the aws_s3_bucket_website_configuration resource, defining the index document as "index.html". This comprehensive script streamlines the process of creating a secure S3 bucket and deploying a static website, providing a robust foundation for web hosting on AWS. By using depends_on in these scenarios, you ensure that the resources are created or modified in the correct order, satisfying any dependencies between them and avoiding potential issues related to resource dependencies.


`outputs.tf`

```hcl
output "website_endpoint" {
  value       = aws_s3_bucket_website_configuration.static_website.website_endpoint
  description = "Link to website"
}
```
In Terraform, the outputs.tf file is used to define output values that can be useful or informative after the infrastructure is deployed. This could include, for example, the URL of the S3 bucket that hosts your website. 

`variables.tf`

The variables.tf file is where you declare and define input variables for your Terraform configuration. Input variables allow you to parameterize your Terraform code, making it more flexible and reusable. 

Below are the variables we are gonna use.
```hcl
variable "bucket_name" {
  type        = string
  description = "(Required) Make sure the bucket name is unique"
}


variable "object_ownership" {
  type        = string
  description = "(Required) Object ownership"
}

variable "block_public_acls" {
  type        = bool
  default     = false
  description = "Whether Amazon S3 should block public ACLs for this bucket."
}

variable "block_public_policy" {
  type        = bool
  default     = false
  description = "Whether Amazon S3 should block public bucket policies for this bucket."
}

variable "ignore_public_acls" {
  type        = bool
  default     = false
  description = "Whether Amazon S3 should ignore public ACLs for this bucket."
}

variable "restrict_public_buckets" {
  type        = bool
  default     = false
  description = "Whether Amazon S3 should restrict public bucket policies for this bucket."
}

variable "acl" {
  type    = string
  default = "public-read"
}

variable "content_type" {
  type        = string
  default     = "text/html"
  description = "Standard MIME type describing the format of the object data, e.g., application/octet-stream. All Valid MIME Types are valid for this input."
}
```


#### Root Module Structure:

```bash
.
├── main.tf
├── index.html
├── modules
│   └── s3_static_website
│       ├── index.html
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── outputs.tf
├── terraform.tf
├── terraform.tfvars
└── variables.tf
```

`index.html`
This file is likely the main HTML file for your static website. It contains the actual content and structure of your chmod calculator web application. It may include HTML tags, CSS styles, and JavaScript code. The content of this file is what users will see when they access your website. In the context of this project, index.html probably contains the user interface for your online chmod calculator.
Now inside the root module, call the s3_static_website module in main.tf

`main.tf`
In the below code, we are making a call to the s3_static_website module.
```hcl
module "s3_static_website" {
  source           = "./modules/s3_static_website"
  bucket_name      = var.bucket_name
  object_ownership = var.object_ownership
}
```
`variables.tf`
In this file, We will define only the required variables, for those, we will provide values in `terraform.tfvars`

```hcl
variable "bucket_name" {
  type        = string
  description = "(Required) Make sure the bucket name is unique"
}


variable "object_ownership" {
  type        = string
  description = "(Required) Object ownership"
}

```
`outputs.tf`
The below code will print the s3 bucket's public endpoint.

```hcl
output "website_endpoint" {
  value       = module.s3_static_website.website_endpoint
  description = "The website endpoint."
}
```
`terraform.tf`
In the below code we are defining what provider and which terraform cloud workspace is going to be used.

```hcl
terraform {
  cloud {
    organization = "aws-test-resources"

    workspaces {
      name = "S3_static_website"
    }
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.31.0"
    }
  }
}
```

`terraform.tfvars`

In this file, we define the exact values of the bucket_name and object_ownership.
 
```hcl
bucket_name      = "chmd-octal-notations"
object_ownership = "BucketOwnerPreferred"
```
Note: Switch to the root module's directory and run the following commands to provision the setup.

```bash
terraform init
```
- This command initializes a new or existing Terraform configuration. It downloads the necessary providers and sets up the working directory.
- The `terraform init` command should be executed once in the project directory or whenever there are changes to the configuration or provider dependencies.


![terraform init](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m0nngzb0uel5g84mk0sj.png)


```bash
terraform plan
```
- This command generates an execution plan based on the current Terraform configuration. It outlines the changes that Terraform will apply to reach the desired state.
- Running a `terraform plan` allows you to review the proposed changes before applying them, providing insights into what resources will be created, modified, or destroyed.

![terraform plan](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccfj0pvfizlm37ackm9g.png)


```bash
terraform apply
```
- This command is used to apply the changes outlined in the execution plan generated by the `terraform plan`.
- When executed, Terraform prompts for confirmation before making any modifications. If the plan looks satisfactory, you can confirm to proceed with the actual deployment of infrastructure.

![terraform apply](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8hkpur9s9feq2d5lab3l.png)

We can check on the console that the bucket is created and we can access using the website endpoint printed in the terminal.


![Infra Created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gp0i1gb4f5w217a9lum.png)


By clicking on the link printed on the terminal we can access our website.

![Final Website](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69d5gasqxiij1nhfwdlj.png)

### Voila We did it.

You can find the whole code in the [ GitHub Repo ](https://github.com/PiyushBagani15/online-chmod-calculator/) 

### Thanks for Reading. Feel Free to ask any questions.