Secure Serverless Static Website on AWS (Terraform)
This project implements a secure, serverless static website architecture on AWS using Amazon S3 as the origin, Amazon CloudFront as the CDN layer, and Terraform as the infrastructure provisioning tool. The goal was to deliver static content securely and reliably while enforcing best practices around access control, metadata correctness, and Infrastructure as Code.
Architecture Overview
- Static site hosted in a private Amazon S3 bucket
- Public access provided through Amazon CloudFront
- Origin Access Identity (OAI) used to prevent direct S3 access
- HTTPS enforced at the CloudFront distribution
- Full environment provisioned and managed using Terraform
Architecture Diagram
Key Engineering Decisions
- Kept the S3 bucket private and restricted access to CloudFront only
- Explicitly defined
Content-Typemetadata in Terraform to prevent CDN rendering issues - Used CloudFront cache invalidation to propagate metadata changes correctly
- Designed the project to be reproducible, auditable, and free of manual console changes
Problem Solved
During deployment, CloudFront initially served the site as a downloadable file rather than rendering
it in the browser. This was traced to incorrect system-defined S3 metadata
(application/octet-stream). The issue was resolved by replacing the S3 object with the
correct MIME type and locking the fix into Terraform to prevent regressions.
Terraform Highlights
resource "aws_s3_object" "index" {
bucket = aws_s3_bucket.site.bucket
key = "index.html"
source = "${path.module}/site/index.html"
content_type = "text/html"
etag = filemd5("${path.module}/site/index.html")
}
S3 Bucket Security
The static website content is stored in a private Amazon S3 bucket. Public access is fully blocked, and access is granted only to CloudFront through an Origin Access Identity (OAI).
resource "aws_s3_bucket" "site" {
bucket = var.site_bucket_name
}
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
}
CloudFront Distribution
Amazon CloudFront is used as the public entry point for the website, providing HTTPS enforcement, global edge caching, and controlled access to the private S3 origin.
resource "aws_cloudfront_distribution" "site" {
enabled = true
default_root_object = "index.html"
origin {
domain_name = aws_s3_bucket.site.bucket_regional_domain_name
origin_id = "s3-site-origin"
s3_origin_config {
origin_access_identity =
aws_cloudfront_origin_access_identity.site.cloudfront_access_identity_path
}
}
default_cache_behavior {
target_origin_id = "s3-site-origin"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
}
}
Origin Access Identity (OAI)
An Origin Access Identity (OAI) is used to allow CloudFront to access the private S3 bucket while preventing all direct public access to S3.
resource "aws_cloudfront_origin_access_identity" "site" {
comment = "OAI for CloudFront private S3 access"
}
Live Demo
https://d3nmn17w739ob6.cloudfront.net/ View the CloudFront Distribution