Skip to content

Instantly share code, notes, and snippets.

@TanyaMushonga
Last active September 30, 2025 20:39
Show Gist options
  • Select an option

  • Save TanyaMushonga/b605d5d2d6cfe379d5b5baa0503af5ca to your computer and use it in GitHub Desktop.

Select an option

Save TanyaMushonga/b605d5d2d6cfe379d5b5baa0503af5ca to your computer and use it in GitHub Desktop.
A production-ready Terraform configuration that provisions secure, scalable, and globally distributed static website infrastructure on AWS using S3, CloudFront, and Certificate Manager

AWS Static Site Infrastructure with Terraform

A production-ready Terraform configuration that provisions secure, scalable, and globally distributed static website infrastructure on AWS using S3, CloudFront, and Certificate Manager.

Architecture Overview

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   User/Browser  │───▶│   CloudFront     │───▶│   S3 Bucket     │
│                 │    │   Distribution   │    │  (Private)      │
│  yourdomain.com │    │                  │    │                 │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                              │                         ▲
                              ▼                         │
                       ┌──────────────────┐           │
                       │  ACM Certificate │           │
                       │   (SSL/HTTPS)    │           │
                       └──────────────────┘           │
                                                       │
                       ┌──────────────────┐           │
                       │      OAC         │───────────┘
                       │ (Origin Access   │
                       │   Control)       │
                       └──────────────────┘

What This Creates

Resource Purpose Key Features
S3 Bucket Static file hosting Private access, versioning, website configuration
CloudFront Distribution Global CDN HTTPS redirect, caching, compression, custom errors
Origin Access Control Secure S3 access Replaces legacy OAI, uses SigV4 signing
ACM Certificate SSL/TLS encryption Free SSL certificate with DNS validation
S3 Bucket Policy Access control Allows only CloudFront to access bucket content

Features

  • Global CDN - CloudFront distribution for lightning-fast content delivery worldwide
  • SSL/TLS Encryption - Automatic HTTPS with AWS Certificate Manager
  • Security Best Practices - Origin Access Control (OAC), private S3 bucket, secure policies
  • Cost-Optimized - Smart caching, compression, and PriceClass_100 for cost efficiency
  • Version Control - S3 bucket versioning enabled for content rollback capabilities
  • SPA-Ready - Custom error handling for Single Page Applications
  • Resource Tagging - Comprehensive tagging strategy for cost allocation and management
  • Infrastructure as Code - Fully reproducible and version-controlled infrastructure

File Structure

aws-static-site/
├── main.tf                    # Main infrastructure configuration
├── variables.tf               # Input variables definition
├── outputs.tf                 # Output values (URLs, IDs, etc.)
├── terraform.tfvars           # Your variable values (not in git)
├── terraform.tfvars.example   # Example variable values
├── LICENSE.txt                # MIT license
└── README.md                  # Documentation

Quick Start

Prerequisites

  • Terraform >= 1.5.0
  • AWS CLI configured with appropriate permissions
  • A domain name (for SSL certificate and custom domain)

Required AWS Permissions

Your AWS user/role needs:

  • s3:* (for S3 bucket management)
  • cloudfront:* (for CloudFront distribution)
  • acm:* (for SSL certificate management)
  • iam:GetRole, iam:PassRole (for service roles)

Deploy Infrastructure

# 1. Clone the repository
git clone https://github.com/TanyaMushonga/terraform-s3_and_cloudfront.git
cd terraform-s3_and_cloudfront

# 2. Configure variables
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your values

# 3. Initialize Terraform
terraform init

# 4. Preview changes
terraform plan

# 5. Deploy infrastructure
terraform apply

Configuration Example

# terraform.tfvars
region = "us-west-2"
bucket_name = "my-awesome-site-2024"
domain_name = "blog.yourdomain.com"
environment = "prod"

tags = {
  Project   = "My Awesome Blog"
  ManagedBy = "Terraform"
  Owner     = "Your Name"
  CostCenter = "Marketing"
}

Key Code Explanations

Terraform Provider Configuration

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

# Default region for S3 and other resources
provider "aws" {
  region = var.region
}

# us-east-1 provider for CloudFront certificate (required by AWS)
provider "aws" {
  alias  = "us_east_1"
  region = "us-east-1"
}

Why two providers? CloudFront SSL certificates must be created in us-east-1, while other resources can be in your preferred region.

S3 Bucket with Security

resource "aws_s3_bucket" "static_site" {
  bucket = var.bucket_name
  tags = merge(var.tags, {
    Name        = var.bucket_name
    Environment = var.environment
  })
}

# Block all public access (CloudFront will access via OAC)
resource "aws_s3_bucket_public_access_block" "static_site" {
  bucket = aws_s3_bucket.static_site.id
  
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

Security First: The bucket is completely private. Only CloudFront can access it through Origin Access Control.

Origin Access Control (Modern Security)

resource "aws_cloudfront_origin_access_control" "static_site" {
  name                              = "${var.bucket_name}-oac"
  description                       = "OAC for ${var.domain_name}"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

Why OAC over OAI? Origin Access Control is the modern, more secure replacement for Origin Access Identity, using SigV4 signing.

CloudFront Distribution

resource "aws_cloudfront_distribution" "static_site" {
  origin {
    domain_name              = aws_s3_bucket.static_site.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.static_site.id
    origin_id                = "S3-${var.bucket_name}"
  }
  
  default_cache_behavior {
    viewer_protocol_policy = "redirect-to-https"  # Force HTTPS
    compress               = true                 # Enable compression
    default_ttl            = 3600                # 1 hour cache
    cached_methods         = ["GET", "HEAD"]     # Cache read operations only
  }
  
  price_class = "PriceClass_100"  # US, Canada, Europe (cost-optimized)
}

Performance & Cost: Configured for optimal caching with geographic cost optimization.

S3 Bucket Policy (Least Privilege)

resource "aws_s3_bucket_policy" "static_site" {
  bucket = aws_s3_bucket.static_site.id
  
  policy = jsonencode({
    Statement = [{
      Effect = "Allow"
      Principal = { Service = "cloudfront.amazonaws.com" }
      Action   = "s3:GetObject"
      Resource = "${aws_s3_bucket.static_site.arn}/*"
      Condition = {
        StringEquals = {
          "AWS:SourceArn" = aws_cloudfront_distribution.static_site.arn
        }
      }
    }]
  })
}

Zero Trust: Only your specific CloudFront distribution can access the bucket.

Deployment Process

After running terraform apply, you'll need to:

  1. Configure DNS: Point your domain to the CloudFront distribution
  2. Validate Certificate: Add DNS validation records to your domain provider
  3. Upload Content: Deploy your static files to the S3 bucket

Cost Estimation

Service Usage Est. Monthly Cost
S3 Standard Storage 1GB $0.023
CloudFront 10GB transfer $0.85
Route 53 DNS queries $0.40
ACM Certificate SSL cert $0.00
Total ~$1.27/month

Security Features

  • Private S3 Bucket - No public access, CloudFront-only access
  • Origin Access Control (OAC) - Modern replacement for OAI
  • HTTPS Enforced - All HTTP traffic redirected to HTTPS
  • IAM Policies - Least-privilege access principles
  • Resource Tagging - Complete resource attribution

Best Practices Included

  • Infrastructure as Code - Version controlled, reproducible deployments
  • Environment Separation - Support for dev/staging/prod environments
  • Cost Optimization - Regional edge locations, smart caching
  • Security by Default - Private resources, encrypted transit
  • Monitoring Ready - CloudWatch integration, access logging support

Common Use Cases

  • Portfolio Websites - Showcase your work globally
  • Documentation Sites - Fast, searchable documentation
  • Landing Pages - Marketing sites with global reach
  • Static Blogs - Generated sites (Jekyll, Hugo, Gatsby)
  • Single Page Applications - React, Vue, Angular apps

Repositories

Infrastructure Code: terraform-s3_and_cloudfront - Complete Terraform configuration for AWS static site infrastructure

Live Example: aws-static-site-deploy - Actual website deployed using this infrastructure with CI/CD automation

Related Resources


Connect & Support

🌐 Portfolio: tanyaradzwatmushonga.me
💼 LinkedIn: Tanyaradzwa T. Mushonga
📂 Infrastructure Repo: terraform-s3_and_cloudfront
🚀 Deployment Repo: aws-static-site-deploy

⭐ If this helped you:

  • Star both repositories
  • Follow me for more DevOps, AWS, and Terraform tutorials
  • Connect on LinkedIn for cloud engineering insights

Built with Terraform and AWS

This infrastructure powers thousands of static sites worldwide with enterprise-grade security, performance, and reliability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment