Provision S3 + CloudFront Static Website Using Terraform (Production Guide)
Build AWS infrastructure using Infrastructure as Code instead of manual setup
I build and deploy cloud-native applications using AWS and DevOps practices. I share practical tutorials on CI/CD pipelines, serverless architectures, and real project learnings, and I’m exploring MLOps.
Introduction
In the previous blogs, we manually created AWS resources such as S3, CloudFront, IAM users, and policies using the AWS Management Console. While this approach works for learning, it quickly becomes inefficient and risky as environments grow.
In real-world DevOps and SRE teams, infrastructure is never managed manually. Clicking through the AWS console for every change leads to inconsistency, human error, and poor scalability.
This is where Infrastructure as Code (IaC) comes in.
In this blog, we will use Terraform to provision and manage AWS infrastructure in a fully automated, secure, and reproducible way, following real production practices.
Prerequisites
AWS account
Terraform installed
AWS CLI configured with an IAM user that has permissions to create IAM, S3, and CloudFront resources
Terraform Modules
Problem with Manual AWS Console Setup
Managing infrastructure manually through the AWS Console introduces several problems:
No version control for infrastructure changes
Difficult to replicate environments (dev, staging, prod)
High chance of misconfiguration
Manual steps are error-prone
Not suitable for team collaboration
Hard to audit who changed what and when
As infrastructure grows, manual setup becomes unmanageable and unsafe for production workloads.
Why Infrastructure as Code (IaC) Matters
Infrastructure as Code means defining your infrastructure using code, not clicks.
With IaC:
Infrastructure is stored in version control (Git)
Changes are reviewed like application code
Environments are consistent and repeatable
Infrastructure can be recreated at any time
Rollbacks are possible
Automation becomes simple and reliable
IaC is a core requirement in modern DevOps, Cloud, and SRE roles.
Terraform in Real-World DevOps
Terraform is one of the most widely used IaC tools in the industry.
In real-world DevOps teams, Terraform is used to:
Provision AWS, Azure, GCP infrastructure
Create IAM users, roles, and policies
Manage networking (VPC, subnets, gateways)
Deploy CloudFront, S3, Load Balancers
Standardize infrastructure using modules
Integrate with CI/CD pipelines
Terraform allows teams to manage infrastructure safely, predictably, and at scale.
What You Will Build in This Blog
By the end of this blog, you will build:
A private S3 bucket using Terraform
A CloudFront distribution with Origin Access Control (OAC)
Secure S3 bucket policy allowing access only from CloudFront
An IAM user and policy for Terraform deployments
A modular Terraform project structure
Production-ready AWS infrastructure using code
This setup mirrors how static websites are deployed in real production environments.
What is Terraform?
Terraform is an Infrastructure as Code (IaC) tool developed by HashiCorp that allows you to define, provision, and manage infrastructure using configuration files.
Infrastructure as Code Tool
Terraform lets you describe your infrastructure in simple configuration files, instead of manually creating resources in the cloud console.
Once defined, Terraform automatically creates and manages those resources for you.
Declarative Configuration
Terraform uses a declarative approach, meaning:
You define what infrastructure you want
Terraform figures out how to create it
You don’t need to write procedural scripts. You simply describe the desired end state.
Reproducible Infrastructure
With Terraform:
Infrastructure can be recreated at any time
Environments remain consistent
No configuration drift
Same code works across teams and regions
This makes Terraform ideal for production systems.
Terraform Project Structure (Modules-Based)
As infrastructure grows, keeping all Terraform code in a single file becomes hard to manage.
In real-world DevOps projects, Terraform is organized using modules to improve readability, reusability, and scalability.
A modules-based structure allows teams to:
Reuse infrastructure components
Maintain clean separation of concerns
Apply best practices consistently
Scale infrastructure safely
This is the recommended approach for production environments.
Why Use Terraform Modules?
Terraform modules help solve common problems in large infrastructures:
Avoid code duplication
Standardize infrastructure patterns
Improve maintainability
Enable team collaboration
Make environments (dev, stage, prod) easy to manage
In short, modules turn Terraform into production-grade infrastructure code.
terraform-static-website/
├── modules/
│ ├── iam/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ │
│ ├── s3/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ │
│ ├── cloudfront/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│
├── main.tf
├── variables.tf
├── outputs.tf
├── providers.tf
├── terraform.tfvars
└── README.md
Structure Explanation
modules/
Contains reusable Terraform modules.
Each module is responsible for one logical component.
modules/iam/
Handles:
IAM user creation
IAM policies
Programmatic access for Terraform / CI/CD
This keeps security and access management isolated and easy to audit.
modules/s3/
Handles:
Private S3 bucket creation
Bucket policies
Versioning and encryption (optional)
The bucket is designed to be accessible only via CloudFront.
modules/cloudfront/
Handles:
CloudFront distribution
Origin Access Control (OAC)
S3 origin configuration
Cache behavior
This ensures secure global content delivery.
Root Files
providers.tf
Defines the AWS provider and region.
main.tf
Calls all modules and connects them together.
variables.tf
Defines input variables for the root module.
terraform.tfvars
Stores environment-specific values (bucket name, region, etc.).
outputs.tf
Exports important values such as:
CloudFront distribution ID
S3 bucket name
IAM user access details
Complete Terraform Implementation (GitHub Repository)
To keep this blog clean and focused on architecture and concepts, the full Terraform implementation is maintained in a GitHub repository.
The repository contains production-ready Terraform code that covers:
👉 Creating IAM User and IAM Policy using Terraform
👉 Provisioning a Private S3 Bucket with CloudFront Origin Access Control (OAC)
👉 Deploying a CloudFront Distribution securely connected to the S3 bucket
👉 Applying correct S3 bucket policy to allow access only via CloudFront
GitHub Repository
🔗 Terraform Code Repository:
👉 https://github.com/nlokeshbabu1/AWS-S3
This repository follows a modules-based Terraform structure and reflects real-world DevOps best practices.
Verification
After applying the Terraform configuration, verify that the infrastructure is working as expected:
The S3 bucket is private
Public access to the S3 bucket is blocked
The S3 bucket policy allows access only from CloudFront
CloudFront distribution status is Deployed
The website is accessible using the CloudFront domain name
Successful verification confirms that the setup is secure, scalable, and production-ready.
Cleanup (Optional but Recommended)
Terraform makes it easy to remove infrastructure when it is no longer required.
To avoid unnecessary AWS costs, the resources can be destroyed using Terraform.
The cleanup steps are documented in the GitHub repository and can be executed safely when needed.
This highlights one of the major benefits of Infrastructure as Code — easy creation and clean teardown of resources.
Conclusion
In this blog, we moved from manual AWS resource creation to a fully automated, Infrastructure as Code approach using Terraform.
By using Terraform modules, we achieved:
Reproducible and version-controlled infrastructure
Secure S3 and CloudFront integration using OAC
Clean separation of concerns using modules
Production-ready AWS infrastructure
This approach reflects how real DevOps and SRE teams manage cloud infrastructure at scale.
In the next blog, we will extend this setup by integrating Terraform with CI/CD pipelines to automate infrastructure provisioning and updates.