AWS VPC 3-Tier Architecture using Terraform
AWS services and components used in this project:
Amazon Virtual Private Cloud (VPC)
Internet Gateway
NAT Gateway
Elastic IP address
Route table
Public Subnet
Private Subnet
Project Summary:
This project demonstrates the deployment of a 3-tier architecture on AWS using Terraform as the Infrastructure as Code (IaC) tool. The architecture consists of public and private subnets across two availability zones (AZs), ensuring high availability and fault tolerance. Below is an overview of the setup:
VPC (Virtual Private Cloud):
The project begins with the creation of a custom VPC to host all resources securely. This isolated virtual network allows for fine-grained control over the resources' access.Subnets:
Public Subnets: These subnets, located in both AZs, are attached to an Internet Gateway, allowing instances within them to communicate with the internet. Resources like NAT Gateways are deployed here.
Private Subnets: Both AZs have private subnets dedicated to hosting EC2 instances and databases. These subnets do not have direct internet access for enhanced security.
Internet Gateway:
An Internet Gateway is deployed to enable outbound communication from the public subnets, providing public instances the ability to connect to the internet.NAT Gateway:
In each availability zone, a NAT Gateway is provisioned within the public subnets to enable instances in private subnets to access the internet for updates and patches, without exposing them to inbound internet traffic.Elastic IP Addresses:
Each NAT Gateway is associated with an Elastic IP address, allowing consistent communication with external networks.Route Tables:
The public subnets are associated with route tables that route internet-bound traffic via the Internet Gateway. Private subnets have route tables that route internet-bound traffic through the NAT Gateway, securing the instances while allowing outbound connections.Tiered Services:
Web Tier: Hosted in public subnets, it handles all internet-facing services.
Application Tier: EC2 instances in the private subnet manage business logic and communicate with the database layer.
Database Tier: Dedicated private subnets ensure secure and isolated database operations.
By leveraging Terraform, the entire infrastructure is automated and can be provisioned with minimal manual intervention, improving efficiency and scalability. The design ensures high availability, security, and flexibility, critical for production environments.
Let’s Dive In fellow enthusiasts,
Step-01: Introduction
Understand about Terraform Modules
Create VPC using
Terraform Modules
Define
Input Variables
for VPC module and reference them in VPC Terraform ModuleDefine
local values
and reference them in VPC Terraform ModuleCreate
terraform.tfvars
to load variable values by default from this fileCreate
vpc.auto
.tfvars
to load variable values by default from this file related to a VPCDefine
Output Values
for VPC
Step-02: v1-vpc-module - Hardcoded Model
Step-02-01: How to make a decision of using the public Registry module?
Understand about Terraform Registry and Modules
We are going to use a VPC Module from Terraform Public Registry
Understand about Authenticity of a module hosted on Public Terraform Registry with HashiCorp Verified Tag
Review the download rate for that module
Review the latest versions and release history of that module
Review our feature needs when using that module and ensure if our need is satisfied use the module else use the standard terraform resource definition appraoch.
Review module inputs, outputs and dependencies too.
Step-02-02: v1-vpc-module
c1-versions.tf
# Terraform Block terraform { required_version = ">= 1.6" # which means any version equal & above 0.14 like 0.15, 0.16 etc and < 1.xx required_providers { aws = { source = "hashicorp/aws" version = ">= 5.0" } } } # Provider Block provider "aws" { region = var.aws_region profile = "default" }
c2-generic-variables.tf
# Input Variables # AWS Region variable "aws_region" { description = "Region in which AWS Resources to be created" type = string default = "us-east-1" }
c3-vpc.tf
# Create VPC Terraform Module module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "2.78.0" # VPC Basic Details name = "vpc-dev" cidr = "10.0.0.0/16" azs = ["us-east-1a", "us-east-1b"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] # Database Subnets create_database_subnet_group = true create_database_subnet_route_table= true database_subnets = ["10.0.151.0/24", "10.0.152.0/24"] #create_database_nat_gateway_route = true #create_database_internet_gateway_route = true # NAT Gateways - Outbound Communication enable_nat_gateway = true single_nat_gateway = true # VPC DNS Parameters enable_dns_hostnames = true enable_dns_support = true public_subnet_tags = { Type = "public-subnets" } private_subnet_tags = { Type = "private-subnets" } database_subnet_tags = { Type = "database-subnets" } tags = { Owner = "som" Environment = "dev" } vpc_tags = { Name = "vpc-dev" } }
Step-03: Execute Terraform Commands
# Working Folder
terraform-manifests/v1-vpc-module
# Terraform Initialize
terraform init
Observation:
1. Verify if modules got downloaded to .terraform folder
# Terraform Validate
terraform validate
# Terraform plan
terraform plan
# Terraform Apply
terraform apply -auto-approve
Observation:
1) Verify VPC
2) Verify Subnets
3) Verify IGW
4) Verify Public Route for Public Subnets
5) Verify no public route for private subnets
6) Verify NAT Gateway and Elastic IP for NAT Gateway
7) Verify NAT Gateway route for Private Subnets
8) Verify no public route or no NAT Gateway route to Database Subnets
9) Verify Tags
# Terraform Destroy
terraform destroy -auto-approve
# Delete Files
rm -rf .terraform*
rm -rf terraform.tfstate*
Step-04: Version Constraints in Terraform with Modules
For modules locking to the exact version is recommended to ensure there will not be any major breakages in production
When depending on third-party modules, require specific versions to ensure that updates only happen when convenient to you
For modules maintained within your organization, specifying version ranges may be appropriate if semantic versioning is used consistently or if there is a well-defined release process that avoids unwanted updates.
Step-05: v2-vpc-module-standardized - Standardized and Generalized
In the next series of steps we are going to standardize the VPC configuration
c1-versions.tf
# Terraform Block terraform { required_version = ">= 1.6" # which means any version equal & above 0.14 like 0.15, 0.16 etc and < 1.xx required_providers { aws = { source = "hashicorp/aws" version = ">= 5.0" } } } # Provider Block provider "aws" { region = var.aws_region profile = "default" }
c2-generic-variables.tf
# Input Variables # AWS Region variable "aws_region" { description = "Region in which AWS Resources to be created" type = string default = "us-east-1" } # Environment Variable variable "environment" { description = "Environment Variable used as a prefix" type = string default = "dev" } # Business Division variable "business_divsion" { description = "Business Division in the large organization this Infrastructure belongs" type = string default = "HR" }
c3-local-values.tf
# Define Local Values in Terraform locals { owners = var.business_divsion environment = var.environment name = "${var.business_divsion}-${var.environment}" common_tags = { owners = local.owners environment = local.environment } }
c4-01-vpc-variables.tf
c4-02-vpc-module.tf
c4-03-vpc-outputs.tf
# VPC Output Values # VPC ID output "vpc_id" { description = "The ID of the VPC" value = module.vpc.vpc_id } # VPC CIDR blocks output "vpc_cidr_block" { description = "The CIDR block of the VPC" value = module.vpc.vpc_cidr_block } # VPC Private Subnets output "private_subnets" { description = "List of IDs of private subnets" value = module.vpc.private_subnets } # VPC Public Subnets output "public_subnets" { description = "List of IDs of public subnets" value = module.vpc.public_subnets } # VPC NAT gateway Public IP output "nat_public_ips" { description = "List of public Elastic IPs created for AWS NAT Gateway" value = module.vpc.nat_public_ips } # VPC AZs output "azs" { description = "A list of availability zones spefified as argument to this module" value = module.vpc.azs }
terraform.tfvars
# Generic Variables aws_region = "us-east-1" environment = "dev" business_divsion = "HR"
vpc.auto.tfvars
# VPC Variables vpc_name = "myvpc" vpc_cidr_block = "10.0.0.0/16" vpc_availability_zones = ["us-east-1a", "us-east-1b"] vpc_public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] vpc_private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] vpc_database_subnets= ["10.0.151.0/24", "10.0.152.0/24"] vpc_create_database_subnet_group = true vpc_create_database_subnet_route_table = true vpc_enable_nat_gateway = true vpc_single_nat_gateway = true
Step-06: Execute Terraform Commands
# Working Folder
terraform-manifests/v2-vpc-module-standardized
# Terraform Initialize
terraform init
# Terraform Validate
terraform validate
# Terraform plan
terraform plan
# Terraform Apply
terraform apply -auto-approve
Observation:
1) Verify VPC
2) Verify Subnets
3) Verify IGW
4) Verify Public Route for Public Subnets
5) Verify no public route for private subnets
6) Verify NAT Gateway and Elastic IP for NAT Gateway
7) Verify NAT Gateway route for Private Subnets
8) Verify no public route or no NAT Gateway route to Database Subnets
9) Verify Tags
Step-13: Clean-Up
# Terraform Destroy
terraform destroy -auto-approve
# Delete Files
rm -rf .terraform*
rm -rf terraform.tfstate*
End Notes:
Do not execute the ‘observation’ parts in your terminal.
c4-01-vpc-variables.tf and c4-02-vpc-module.tf had some formatting issues since Hashnode doesn’t support HCL, and so I’ve put the github links to those files, please refer to them.
Hashnode doesn’t have HCL option for pasting code so I have set it to plain text, save the files with the given respective extensions (.tf and .tfvars).
Thank You for reading this far, I hope the blog helps in your terraform with AWS journey fellow enthusiast.
Subscribe to my newsletter
Read articles from Dwaipayan Som directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by