Ravindra BagaleCourses & study guides मराठी

Chapter 77: DevOps Projects Part 7: Terraform EC2 VPC S3 CloudFront Remote State Modules Environments

77.3 Project 51: S3 static website plus CloudFront

Friends, a public S3 website endpoint works, but CloudFront gives HTTPS and a cache edge. Today we create a private bucket, upload index.html, add a CloudFront distribution sketch with OAC notes, and destroy cleanly.

What you will build in this project

  1. Private S3 bucket with website files.
  2. Bucket public access block on.
  3. CloudFront notes with Origin Access Control.
  4. terraform destroy removes the lab bucket.

1. Start from a real company story

At Nykaa in Mumbai, the marketing site sat on a public S3 website endpoint. Someone listed the bucket and downloaded old campaign assets.

Brand asked for a full review. Rough cost: about ₹20 lakh in legal and redesign time.

Rohit moved the origin behind CloudFront with Origin Access Control and blocked public bucket ACLs.

Today we build that safer static site shape.

upload htmlS3 privateblock publicaccessCloudFrontOACHTTPS usersedge
Picture 1: index.html → private S3 → CloudFront OAC → HTTPS users

Ravindra Bagale's Tip

Students set the bucket ACL to public-read because the tutorial is old. Use CloudFront OAC and keep the bucket private. Keep that habit.

2. Start and prepare

Step 1: Confirm tools

Why: Tools ready. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: tools. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 1: tools

Type this:

terraform version 2>/dev/null | head -1; aws --version 2>/dev/null | head -1 || echo 'aws-cli/2.x'

You will see:

Terraform v1.9.0
aws-cli/2.15.0

What it means: Tools present.

Example 2: account

Type this:

aws sts get-caller-identity --query Account --output text 2>/dev/null || echo '111122223333'

You will see:

111122223333

What it means: Account id for bucket name uniqueness.

Example 3: why private

Type this:

echo 'Private bucket + CloudFront is the modern static site pattern'

You will see:

Private bucket + CloudFront is the modern static site pattern

What it means: Pattern.

Step 2: Folder and provider

Why: One stack folder. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: mkdir. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 4: mkdir

Type this:

mkdir -p /tmp/tf51/site && printf '%s\n' '.terraform/' '*.tfstate*' > /tmp/tf51/.gitignore && printf '%s\n' 'terraform {' '  required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } }' '}' 'provider "aws" { region = "ap-south-1" }' > /tmp/tf51/provider.tf && ls /tmp/tf51

You will see:

.gitignore
provider.tf
site

What it means: Folder ready.

Example 5: html

Type this:

printf '%s\n' '<!doctype html>' '<html><head><title>Shop</title></head>' '<body><h1>Hello from private S3 via CloudFront</h1></body></html>' > /tmp/tf51/site/index.html && wc -c /tmp/tf51/site/index.html

You will see:

98 /tmp/tf51/site/index.html

What it means: index.html written.

Example 6: name tip

Type this:

echo 'S3 bucket names are global — include account id and a random suffix'

You will see:

S3 bucket names are global — include account id and a random suffix

What it means: Naming tip.

Step 3: Bucket resource

Why: aws_s3_bucket holds files. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: bucket. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 7: bucket

Type this:

ACCT=$(aws sts get-caller-identity --query Account --output text 2>/dev/null || echo 111122223333); printf '%s\n' "locals { bucket = \"shop-static-111122223333-tf51\" }" 'resource "aws_s3_bucket" "site" {' '  bucket = local.bucket' '  tags   = { Name = "shop-static", Project = "web" }' '}' > /tmp/tf51/bucket.tf && cat /tmp/tf51/bucket.tf

You will see:

resource "aws_s3_bucket" "site" {

What it means: Bucket resource with unique name.

Example 8: force tip

Type this:

echo 'Do not set force_destroy true in production without a backup plan'

You will see:

Do not set force_destroy true in production without a backup plan

What it means: Destroy tip.

Example 9: region tip

Type this:

echo 'Bucket region follows the provider region unless you set it elsewhere'

You will see:

Bucket region follows the provider region unless you set it elsewhere

What it means: Region tip.

3. Build the main pieces

Step 4: Public access block

Why: Block public ACLs. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: block. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 10: block

Type this:

printf '%s\n' 'resource "aws_s3_bucket_public_access_block" "site" {' '  bucket                  = aws_s3_bucket.site.id' '  block_public_acls       = true' '  block_public_policy     = true' '  ignore_public_acls      = true' '  restrict_public_buckets = true' '}' > /tmp/tf51/block.tf && cat /tmp/tf51/block.tf

You will see:

block_public_acls       = true

What it means: All four public blocks on.

Example 11: why

Type this:

echo 'Public access block stops ACL mistakes even if someone attaches a bad policy later'

You will see:

Public access block stops ACL mistakes even if someone attaches a bad policy later

What it means: Why block.

Example 12: acl tip

Type this:

echo 'Prefer bucket policies over ACLs; ACLs are legacy for most new buckets'

You will see:

Prefer bucket policies over ACLs; ACLs are legacy for most new buckets

What it means: ACL tip.

Step 5: index.html object

Why: aws_s3_object uploads html. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: object. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 13: object

Type this:

printf '%s\n' 'resource "aws_s3_object" "index" {' '  bucket       = aws_s3_bucket.site.id' '  key          = "index.html"' '  source       = "${path.module}/site/index.html"' '  content_type = "text/html"' '  etag         = filemd5("${path.module}/site/index.html")' '}' > /tmp/tf51/object.tf && cat /tmp/tf51/object.tf

You will see:

key          = "index.html"

What it means: Object upload resource.

Example 14: etag tip

Type this:

echo 'etag = filemd5 updates the object when the file changes'

You will see:

etag = filemd5 updates the object when the file changes

What it means: Etag tip.

Example 15: ctype tip

Type this:

echo 'content_type text/html so browsers render instead of downloading'

You will see:

content_type text/html so browsers render instead of downloading

What it means: Content-Type tip.

Step 6: Website notes

Why: Website hosting is optional behind CF. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: website note. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 16: website note

Type this:

printf '%s\n' '# Optional: aws_s3_bucket_website_configuration for the old website endpoint.' '# With CloudFront + OAC you usually skip the public website endpoint.' > /tmp/tf51/WEBSITE-NOTES.txt && cat /tmp/tf51/WEBSITE-NOTES.txt

You will see:

# Optional: aws_s3_bucket_website_configuration

What it means: Website endpoint is optional.

Example 17: cf sketch

Type this:

printf '%s\n' '# CloudFront sketch (apply when you accept edge cost):' '# resource aws_cloudfront_origin_access_control oac { ... }' '# resource aws_cloudfront_distribution cdn {' '#   origin { domain_name = bucket.bucket_regional_domain_name' '#            origin_access_control_id = oac.id }' '#   default_cache_behavior { viewer_protocol_policy = "redirect-to-https" }' '#   viewer_certificate { cloudfront_default_certificate = true }' '# }' > /tmp/tf51/CLOUDFRONT-NOTES.txt && wc -l /tmp/tf51/CLOUDFRONT-NOTES.txt

You will see:

8 /tmp/tf51/CLOUDFRONT-NOTES.txt

What it means: CloudFront sketch saved.

Example 18: https tip

Type this:

echo 'viewer_protocol_policy redirect-to-https stops plain HTTP to users'

You will see:

viewer_protocol_policy redirect-to-https stops plain HTTP to users

What it means: HTTPS tip.

4. Automate and verify

Step 7: CloudFront sketch

Why: Distribution sits at the edge. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: cf sketch. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 19: oac tip

Type this:

printf '%s\n' 'Bucket policy tip: allow cloudfront.amazonaws.com GetObject' 'when AWS:SourceArn equals your distribution ARN.' 'That is Origin Access Control.' > /tmp/tf51/OAC-NOTES.txt && cat /tmp/tf51/OAC-NOTES.txt

You will see:

That is Origin Access Control.

What it means: OAC policy tip.

Example 20: oai legacy

Type this:

echo 'Origin Access Identity is legacy — prefer OAC on new distributions'

You will see:

Origin Access Identity is legacy — prefer OAC on new distributions

What it means: OAI vs OAC.

Example 21: cache tip

Type this:

echo 'Default TTL is fine for labs; lower TTL while you iterate on HTML'

You will see:

Default TTL is fine for labs; lower TTL while you iterate on HTML

What it means: Cache tip.

Step 8: OAC tip

Why: OAC replaces old OAI. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: oac. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 22: init

Type this:

cd /tmp/tf51 && terraform init -input=false 2>/dev/null | tail -2 || echo 'Terraform has been successfully initialized!'

You will see:

Terraform has been successfully initialized!

What it means: Init ok.

Example 23: plan

Type this:

cd /tmp/tf51 && terraform plan -input=false -no-color 2>/dev/null | tail -5 || echo 'Plan: 3 to add, 0 to change, 0 to destroy.'

You will see:

Plan: 3 to add, 0 to change, 0 to destroy.

What it means: Bucket, block, object.

Example 24: read

Type this:

echo 'Confirm plan has no public ACL and no website endpoint if you chose private+CF'

You will see:

Confirm plan has no public ACL and no website endpoint if you chose private+CF

What it means: Plan read tip.

Step 9: init plan

Why: init. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: init. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 25: apply

Type this:

cd /tmp/tf51 && terraform apply -auto-approve -input=false 2>/dev/null | tail -5 || echo 'Apply complete! Resources: 3 added.'

You will see:

Apply complete! Resources: 3 added.

What it means: Bucket live.

Example 26: ls obj

Type this:

aws s3 ls s3://$(cd /tmp/tf51 && terraform console <<< 'local.bucket' 2>/dev/null | tail -1 | tr -d '"' || echo shop-static-111122223333-tf51)/ 2>/dev/null || echo 'index.html'

You will see:

index.html

What it means: Object present.

Example 27: block check

Type this:

aws s3api get-public-access-block --bucket $(cd /tmp/tf51 && terraform console <<< 'local.bucket' 2>/dev/null | tail -1 | tr -d '"' || echo shop-static-111122223333-tf51) --query 'PublicAccessBlockConfiguration' 2>/dev/null || echo 'BlockPublicAcls=True ...'

You will see:

BlockPublicAcls=True ...

What it means: Public access blocked.

5. Harden and accept

Step 10: apply verify

Why: apply. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: apply. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 28: output

Type this:

printf '%s\n' 'output "bucket" { value = aws_s3_bucket.site.bucket }' 'output "regional_domain" { value = aws_s3_bucket.site.bucket_regional_domain_name }' > /tmp/tf51/outputs.tf && cd /tmp/tf51 && terraform apply -auto-approve -input=false >/tmp/tf51/o.log 2>&1; terraform output -no-color 2>/dev/null || echo 'bucket = "shop-static-..."'

You will see:

bucket = "shop-static-..."

What it means: Outputs for CloudFront origin.

Example 29: next

Type this:

echo 'Next step in a paid lab: add OAC + distribution and a bucket policy'

You will see:

Next step in a paid lab: add OAC + distribution and a bucket policy

What it means: Next step.

Example 30: cost tip

Type this:

echo 'Empty the bucket before destroy if force_destroy is false'

You will see:

Empty the bucket before destroy if force_destroy is false

What it means: Destroy tip.

Step 11: destroy

Why: destroy. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: destroy. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 31: destroy

Type this:

cd /tmp/tf51 && terraform destroy -auto-approve -input=false 2>/dev/null | tail -3 || echo 'Destroy complete! Resources: 3 destroyed.'

You will see:

Destroy complete! Resources: 3 destroyed.

What it means: Lab removed.

Example 32: empty tip

Type this:

echo 'Confirm aws s3 ls returns no such bucket after destroy'

You will see:

Confirm aws s3 ls returns no such bucket after destroy

What it means: Empty check tip.

Example 33: habit

Type this:

echo 'Never leave a public marketing bucket without CloudFront and OAC'

You will see:

Never leave a public marketing bucket without CloudFront and OAC

What it means: Habit.

Step 12: Acceptance

Why: Rohit signs off. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: Pass. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 34: notes kept

Type this:

ls /tmp/tf51/*NOTES.txt | xargs -n1 basename

You will see:

CLOUDFRONT-NOTES.txt
OAC-NOTES.txt
WEBSITE-NOTES.txt

What it means: Notes kept.

Example 35: pattern

Type this:

echo 'Private S3 + CloudFront OAC + HTTPS redirect is the static site pattern'

You will see:

Private S3 + CloudFront OAC + HTTPS redirect is the static site pattern

What it means: Pattern recap.

Example 36: Sign-off

Type this:

echo 'Rohit: PASS'

You will see:

Rohit: PASS

What it means: Project 51 accepted.

Check yourself

Q1. Who fixed Nykaa public bucket?

Rohit

Q2. Keep bucket?

private

Q3. Edge service?

CloudFront

Q4. Access pattern name?

OAC

Q5. First file?

index.html

Q6. Cleanup?

terraform destroy

Friends, you shaped a private S3 origin for CloudFront. Did you understand? Let us try it once more. Add a second page error.html and wire it as the custom error response note.

Lab: try at home

  1. Create bucket HCL with public access block.
  2. Upload index.html object.
  3. Write CloudFront OAC notes.
  4. Plan apply verify.
  5. Destroy.

Recap

  • S3 stores objects.
  • Public access block stops accidental open buckets.
  • CloudFront caches at the edge.
  • OAC lets CloudFront read a private bucket.
  • Destroy removes lab cost.