| name | terraform-infrastructure |
| description | Infrastructure as Code using Terraform with modular components, state management, and multi-cloud deployments. Use for provisioning and managing cloud resources. |
Terraform Infrastructure
Overview
Build scalable infrastructure as code with Terraform, managing AWS, Azure, GCP, and on-premise resources through declarative configuration, remote state, and automated provisioning.
When to Use
- Cloud infrastructure provisioning
- Multi-environment management (dev, staging, prod)
- Infrastructure versioning and code review
- Cost tracking and resource optimization
- Disaster recovery and environment replication
- Automated infrastructure testing
- Cross-region deployments
Implementation Examples
1. AWS Infrastructure Module
# terraform/main.tf
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# Remote state configuration
backend "s3" {
bucket = "terraform-state-prod"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
Project = var.project_name
}
}
}
# VPC and networking
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-${count.index + 1}"
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnets[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.project_name}-private-${count.index + 1}"
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-igw"
}
}
# NAT Gateway for private subnets
resource "aws_eip" "nat" {
count = length(var.public_subnets)
domain = "vpc"
tags = {
Name = "${var.project_name}-eip-${count.index + 1}"
}
depends_on = [aws_internet_gateway.main]
}
resource "aws_nat_gateway" "main" {
count = length(var.public_subnets)
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = {
Name = "${var.project_name}-nat-${count.index + 1}"
}
depends_on = [aws_internet_gateway.main]
}
# Route tables
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${var.project_name}-public-rt"
}
}
resource "aws_route_table" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main[count.index].id
}
tags = {
Name = "${var.project_name}-private-rt-${count.index + 1}"
}
}
# Route table associations
resource "aws_route_table_association" "public" {
count = length(var.public_subnets)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private" {
count = length(var.private_subnets)
subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private[count.index].id
}
# Security Group
resource "aws_security_group" "alb" {
name = "${var.project_name}-alb-sg"
description = "Security group for ALB"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-alb-sg"
}
}
# Application Load Balancer
resource "aws_lb" "main" {
name = "${var.project_name}-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = aws_subnet.public[*].id
enable_deletion_protection = var.environment == "production" ? true : false
tags = {
Name = "${var.project_name}-alb"
}
}
# Data source for availability zones
data "aws_availability_zones" "available" {
state = "available"
}
2. Variables and Outputs
# terraform/variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "environment" {
description = "Environment name"
type = string
validation {
condition = contains(["dev", "staging", "production"], var.environment)
error_message = "Environment must be dev, staging, or production."
}
}
variable "project_name" {
description = "Project name for resource naming"
type = string
}
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
variable "public_subnets" {
description = "Public subnet CIDR blocks"
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
variable "private_subnets" {
description = "Private subnet CIDR blocks"
type = list(string)
default = ["10.0.10.0/24", "10.0.11.0/24"]
}
# terraform/outputs.tf
output "vpc_id" {
description = "VPC ID"
value = aws_vpc.main.id
}
output "vpc_cidr" {
description = "VPC CIDR block"
value = aws_vpc.main.cidr_block
}
output "public_subnet_ids" {
description = "Public subnet IDs"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "Private subnet IDs"
value = aws_subnet.private[*].id
}
output "alb_dns_name" {
description = "DNS name of the ALB"
value = aws_lb.main.dns_name
}
output "alb_arn" {
description = "ARN of the ALB"
value = aws_lb.main.arn
}
3. Terraform Deployment Script
#!/bin/bash
# deploy-terraform.sh - Terraform deployment automation
set -euo pipefail
ENVIRONMENT="${1:-dev}"
ACTION="${2:-plan}"
TF_DIR="terraform"
echo "Terraform $ACTION for environment: $ENVIRONMENT"
cd "$TF_DIR"
# Initialize Terraform
echo "Initializing Terraform..."
terraform init -upgrade
# Format and validate
echo "Validating Terraform configuration..."
terraform fmt -recursive -check .
terraform validate
# Create/select workspace
echo "Creating/selecting workspace: $ENVIRONMENT"
terraform workspace select -or-create "$ENVIRONMENT"
# Plan or apply
case "$ACTION" in
plan)
echo "Creating Terraform plan..."
terraform plan \
-var-file="environments/$ENVIRONMENT.tfvars" \
-out="tfplan-$ENVIRONMENT"
;;
apply)
echo "Applying Terraform changes..."
terraform apply \
-var-file="environments/$ENVIRONMENT.tfvars" \
-auto-approve
;;
destroy)
echo "WARNING: Destroying infrastructure in $ENVIRONMENT"
read -p "Are you sure? (yes/no): " confirm
if [ "$confirm" = "yes" ]; then
terraform destroy \
-var-file="environments/$ENVIRONMENT.tfvars" \
-auto-approve
fi
;;
*)
echo "Unknown action: $ACTION"
exit 1
;;
esac
echo "Terraform $ACTION complete!"
Best Practices
✅ DO
- Use remote state (S3, Terraform Cloud)
- Implement state locking (DynamoDB)
- Organize code into modules
- Use workspaces for environments
- Apply tags consistently
- Use variables for flexibility
- Implement code review before apply
- Keep sensitive data in separate variable files
❌ DON'T
- Store state files locally in git
- Use hardcoded values
- Mix environments in single state
- Skip terraform plan review
- Use root module for everything
- Store secrets in code
- Disable state locking
Terraform Commands
terraform init # Initialize Terraform
terraform validate # Validate configuration
terraform fmt # Format code
terraform plan # Preview changes
terraform apply # Apply changes
terraform destroy # Remove resources
terraform workspace # Manage workspaces