<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Abhishek Paul</title>
    <description>The latest articles on Forem by Abhishek Paul (@abhishekpawl).</description>
    <link>https://forem.com/abhishekpawl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F813599%2F9ddee101-68f1-4320-b045-862db2ee0d58.jpeg</url>
      <title>Forem: Abhishek Paul</title>
      <link>https://forem.com/abhishekpawl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/abhishekpawl"/>
    <language>en</language>
    <item>
      <title>Automate hosting a simple web app on Amazon S3 using Terraform</title>
      <dc:creator>Abhishek Paul</dc:creator>
      <pubDate>Tue, 13 Jun 2023 11:42:50 +0000</pubDate>
      <link>https://forem.com/abhishekpawl/automate-hosting-a-simple-web-app-on-amazon-s3-using-terraform-mga</link>
      <guid>https://forem.com/abhishekpawl/automate-hosting-a-simple-web-app-on-amazon-s3-using-terraform-mga</guid>
      <description>&lt;p&gt;Hello! I finally started writing blogs and to start with here's a little blog from the tools that I've been learning to use lately.&lt;/p&gt;

&lt;p&gt;AUTOMATION - cool isn't it? (if you're trying to crawl into DevOps like me)&lt;/p&gt;

&lt;h3&gt;
  
  
  Thumb rule
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The most basic and important rule that I learned in this journey, is that one must know how to do 'it' manually, before writing scripts to automate 'it'.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The repository to follow along with the blog:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/abhishekpawl"&gt;
        abhishekpawl
      &lt;/a&gt; / &lt;a href="https://github.com/abhishekpawl/tf-scorekeeper-s3"&gt;
        tf-scorekeeper-s3
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This is a simple demonstration on how to write scripts in Terraform to automate hosting a simple web app in Amazon S3.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
S3 automation&lt;/h1&gt;
&lt;h2&gt;
Task 1&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;bucket name&lt;/li&gt;
&lt;li&gt;aws region&lt;/li&gt;
&lt;li&gt;uncheck block all public access&lt;/li&gt;
&lt;li&gt;(DON'T) enable bucket versioning&lt;/li&gt;
&lt;li&gt;create bucket&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Task 2&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;upload object - index.html&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Task 3&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;edit bucket policy&lt;/li&gt;
&lt;li&gt;S3 bucket policy&lt;/li&gt;
&lt;li&gt;ALLOW&lt;/li&gt;
&lt;li&gt;principal: *&lt;/li&gt;
&lt;li&gt;bucket-name/*&lt;/li&gt;
&lt;li&gt;GetObject&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Task 4&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;bucket $\to$ properties&lt;/li&gt;
&lt;li&gt;static website hosting
&lt;ol&gt;
&lt;li&gt;edit&lt;/li&gt;
&lt;li&gt;enable&lt;/li&gt;
&lt;li&gt;specify index document&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/abhishekpawl/tf-scorekeeper-s3"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;So, let's divide the blog into two parts: the manual way and the automatic way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual
&lt;/h2&gt;

&lt;p&gt;So, let's first walk through the process of hosting a web app on S3 manually.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Login into your AWS management console (obviously using your IAM user 😅).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search for the S3 management console from the services and visit it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a bucket.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Give in your bucket name.&lt;/li&gt;
&lt;li&gt;Choose your AWS region, although S3 is a global service.&lt;/li&gt;
&lt;li&gt;Uncheck &lt;strong&gt;Block &lt;em&gt;all&lt;/em&gt; public access&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create it.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get into the bucket (click on it).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upload the &lt;strong&gt;&lt;em&gt;index.html&lt;/em&gt;&lt;/strong&gt; object (file).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under the &lt;strong&gt;Properties&lt;/strong&gt; tab, scroll down to the bottom and enable &lt;strong&gt;&lt;em&gt;Static website hosting&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Still, the website won't be accessible through the public URL. Only the authorized IAM user (i.e. you) will be able to access it using the pre-signed URL. But, you had earlier unchecked &lt;strong&gt;Block &lt;em&gt;all&lt;/em&gt; public access&lt;/strong&gt;, right?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;So, now you need to update the S3 bucket policy so that anyone can access this web app. Under the &lt;strong&gt;Permissions&lt;/strong&gt; tab, you need to &lt;strong&gt;Edit&lt;/strong&gt; the bucket policy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;We'll use the interactive &lt;strong&gt;Policy generator&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Type of policy: &lt;strong&gt;S3 bucket policy&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Statement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Effect: &lt;strong&gt;Allow&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Principal: &lt;strong&gt;*&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;AWS Service: &lt;strong&gt;Amazon S3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Actions: &lt;strong&gt;GetObject&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Amazon Resource Name (ARN): &lt;strong&gt;&amp;lt;bucket-name&amp;gt;/*&lt;/strong&gt; (you would need this policy for all the objects in our bucket, right?)&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Add statement&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;strong&gt;Generate Policy&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the policy in JSON format to the clipboard.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go back and paste the policy in the &lt;strong&gt;Bucket policy&lt;/strong&gt; field.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that you know how to do it manually, let's move over to automating it. Automating the whole process using Terraform is pretty simple if you know how to use the docs and all you need to automate is the manual steps. HAHA!&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's automate 'it'
&lt;/h2&gt;

&lt;p&gt;Firstly, for automating this whole process from our local computer, you first need to tell AWS that the script is being run by authorized personnel so that AWS allows for the management of its resources. For this purpose, you need to create access keys for your IAM user.&lt;/p&gt;

&lt;p&gt;Now, let's move on to writing the scripts.&lt;/p&gt;

&lt;p&gt;Firstly, you need to ask Terraform to download plugins for AWS by providing the provider configurations.&lt;/p&gt;

&lt;p&gt;Write a file &lt;em&gt;provider.tf&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# provider.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.2.0"
    }
  }
}

provider "aws" {
  region     = var.region
  access_key = var.access_key
  secret_key = var.secret_key
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;em&gt;var&lt;/em&gt; represents that the &lt;em&gt;region&lt;/em&gt;, &lt;em&gt;access_key&lt;/em&gt; and &lt;em&gt;secret_key&lt;/em&gt; are defined as variables, for which you write the &lt;em&gt;variable.tf&lt;/em&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# variable.tf
variable "region" {
  type = string
}

variable "access_key" {
  type = string
}

variable "secret_key" {
  type = string
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have defined the variables but haven't declared them yet. To declare the variables, you write the &lt;em&gt;terraform.tfvars&lt;/em&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# terraform.tfvars
region = "ap-south-1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where are &lt;em&gt;access_key&lt;/em&gt; and &lt;em&gt;secret_key&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Well, it's never a good practice to write out your &lt;em&gt;access_key&lt;/em&gt; and &lt;em&gt;secret_key&lt;/em&gt; in public. So, you may define them as environment variables as follows, in the terminal. If we define our environment variables with the prefix &lt;em&gt;TF_VAR_&lt;/em&gt; then Terraform automatically reads them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export TF_VAR_access_key=XXXXXXXXXXXXXXXXXXXX&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export TF_VAR_secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that, you have configured the provider information, run &lt;code&gt;terraform init&lt;/code&gt; to start with Terraform (downloading the required plugins).&lt;/p&gt;

&lt;p&gt;Following, the manual steps, the first thing you have next is to create an S3 bucket, or rather, automate creating an S3 bucket. Write a configuration file &lt;em&gt;bucket.tf&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# bucket.tf
resource "aws_s3_bucket" "tf_bucket" {
  bucket = "tf-scorekeeper-v1"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you need to automate the process of unchecking &lt;strong&gt;Block &lt;em&gt;all&lt;/em&gt; public access&lt;/strong&gt; by writing the configuration file &lt;em&gt;bucket-public-access.tf&lt;/em&gt; for it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# bucket-public-access.tf
resource "aws_s3_bucket_public_access_block" "unblock_public_access" {
  bucket = aws_s3_bucket.tf_bucket.id

  block_public_policy     = false
  block_public_acls       = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, for a change, first configure the bucket at once. So write the config file &lt;em&gt;bucket-policy.tf&lt;/em&gt; to configure the bucket policy, which was the last step while doing all of it manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# bucket-policy.tf
resource "aws_s3_bucket_policy" "tf_public_read_access" {
  bucket = aws_s3_bucket.tf_bucket.id
  policy = &amp;lt;&amp;lt;EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
        "Principal": "*",
      "Action": [ "s3:GetObject" ],
      "Resource": [
        "${aws_s3_bucket.test-bucket.arn}",
        "${aws_s3_bucket.test-bucket.arn}/*"
      ]
    }
  ]
}
EOF
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add in the HTML file &lt;em&gt;index.html&lt;/em&gt; that will serve as the web app. The file is quite long, so skipping it here, but it is provided in the GitHub repository.&lt;/p&gt;

&lt;p&gt;Now, you need to automate the steps to upload the object i.e. the &lt;em&gt;index.html&lt;/em&gt; file. For this, write the &lt;em&gt;object.tf&lt;/em&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# object.tf
resource "aws_s3_object" "object" {
  bucket       = aws_s3_bucket.tf_bucket.id
  key          = "index.html"
  source       = "index.html"
  content_type = "text/html"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you need to automate the step of enabling the &lt;em&gt;Static website hosting&lt;/em&gt; for S3. So, you write the &lt;em&gt;website.tf&lt;/em&gt; config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# website.tf
resource "aws_s3_bucket_website_configuration" "tf_website" {
  bucket = aws_s3_bucket.tf_bucket.id

  index_document {
    suffix = "index.html"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, it's time to run all the terraform commands.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;terraform fmt&lt;/code&gt; to apply proper formatting to the config files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;terraform plan&lt;/code&gt; to check what Terraform is planning to perform on running the apply command. It should show something like&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IQ5k0U-e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1686652565777/b446c72f-a210-44f3-aea0-963f22605541.png%2520align%3D%2522center%2522" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IQ5k0U-e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1686652565777/b446c72f-a210-44f3-aea0-963f22605541.png%2520align%3D%2522center%2522" alt="" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, run &lt;code&gt;terraform apply --auto-approve&lt;/code&gt; to apply the changes and &lt;strong&gt;&lt;em&gt;AUTOMATE&lt;/em&gt;&lt;/strong&gt; the whole process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;T.B.: In case of an AccessDenied error, run the &lt;code&gt;terraform apply --auto-approve&lt;/code&gt; command once again and you're done.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, you may check your web app.&lt;/p&gt;

&lt;p&gt;Visit the S3 management console, click on your bucket and under the &lt;strong&gt;Properties&lt;/strong&gt; tab, scroll down to the &lt;em&gt;Static website hosting&lt;/em&gt; section and visit the URL. Note, it's not the pre-signed one. You'll see your web app, like mine below (8-2 haha).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SRj5waz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1686653122560/fd6190d9-d027-4e3f-ac4d-e52b58954039.png%2520align%3D%2522center%2522" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRj5waz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1686653122560/fd6190d9-d027-4e3f-ac4d-e52b58954039.png%2520align%3D%2522center%2522" alt="" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, I'm still trying to figure out ways to tackle the silly error at the end. I have gone through the docs repeatedly, Stack Overflow, Reddit and other discussion forums but haven't found any other solution yet.&lt;/p&gt;

&lt;p&gt;As of now, I have destroyed my resources by running the &lt;code&gt;terraform destroy --auto-approve&lt;/code&gt; command, which you may also want to do. :/&lt;/p&gt;

&lt;p&gt;Hey! Finally, &lt;strong&gt;THANKS&lt;/strong&gt; ❤️ for going through my FIRST blog and yes, if you have a solution to the silly little error at the end, please share it with me. :D&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>terraform</category>
      <category>devops</category>
    </item>
    <item>
      <title>Hello, world!</title>
      <dc:creator>Abhishek Paul</dc:creator>
      <pubDate>Sat, 12 Feb 2022 03:28:56 +0000</pubDate>
      <link>https://forem.com/abhishekpawl/hello-world-2c2b</link>
      <guid>https://forem.com/abhishekpawl/hello-world-2c2b</guid>
      <description>&lt;p&gt;That's the first thing yo do when you start coding, isn't it?&lt;/p&gt;

&lt;p&gt;So be it for the title.&lt;/p&gt;

&lt;p&gt;Well, so this is my first post here. If you're seeing this you can check out my projects &lt;a href="https://github.com/abhishekpawl" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As for my first post, I recently built this little utility tool to help fasten up things for me and might just help you too. Be sure to check this out add it to your chrome browser.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/abhishekpawl/localhost" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a snippet of the same.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q7rxrqaz4nexkjdtsuo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q7rxrqaz4nexkjdtsuo.gif" alt="Snippet"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
