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.
मित्रांनो, public S3 website चालते, पण CloudFront HTTPS आणि cache देते. आज private bucket, index.html, CloudFront OAC notes, destroy.
दोस्तों, public S3 website चलता है, पर CloudFront HTTPS और cache देता है. आज private bucket, index.html, CloudFront OAC notes, destroy.
What you will build in this project
- Private S3 bucket with website files.
- Bucket public access block on.
- CloudFront notes with Origin Access Control.
- 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.
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.
Students जुना tutorial पाहून bucket public-read करतात. CloudFront OAC वापरा, bucket private ठेवा. सवय ठेवा.
Students पुरानी tutorial देख bucket public-read करते हैं. CloudFront OAC इस्तेमाल करें, bucket private रखें. आदत रखिए.
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.
मित्रांनो, तुम्ही CloudFront साठी private S3 origin तयार केला. error.html दुसरे page म्हणून टाका.
दोस्तों, आपने CloudFront के लिए private S3 origin बनाया. error.html दूसरा page के रूप में डालें.
Lab: try at home
- Create bucket HCL with public access block.
- Upload index.html object.
- Write CloudFront OAC notes.
- Plan apply verify.
- 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.