TerraformAWSInfrastructureAutomation
Infrastructure as Code with Terraform: From Zero to Production
Learn how to manage cloud infrastructure as code using Terraform — covering state management, modules, workspaces, and real-world AWS infrastructure patterns for production environments.
November 18, 2025·Phan Minh Anh
What is Infrastructure as Code?
Infrastructure as Code (IaC) means managing your servers, networks, and cloud resources through version-controlled configuration files rather than manual clicks in a console. Terraform is the industry standard for this.
Why Terraform?
- Provider-agnostic: works with AWS, Azure, GCP, and 1000+ providers
- Declarative: describe the desired state, Terraform figures out how to get there
- State management: tracks what's currently deployed vs. what's defined
Project Structure
terraform/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── ec2/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── environments/
│ ├── staging/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ └── production/
│ ├── main.tf
│ └── terraform.tfvars
└── backend.tf
Remote State Configuration
Always use remote state in production:
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "production/terraform.tfstate"
region = "ap-southeast-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Creating a VPC Module
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.project_name}-private-${count.index + 1}"
}
}
Using the Module
# environments/production/main.tf
module "vpc" {
source = "../../modules/vpc"
project_name = "myapp"
environment = "production"
vpc_cidr = "10.0.0.0/16"
availability_zones = ["ap-southeast-1a", "ap-southeast-1b", "ap-southeast-1c"]
}
Key Terraform Commands
# Initialize (download providers and modules)
terraform init
# Preview changes without applying
terraform plan -var-file=terraform.tfvars
# Apply changes
terraform apply -var-file=terraform.tfvars
# Destroy infrastructure
terraform destroy -var-file=terraform.tfvars
# Show current state
terraform show
Best Practices
- Never commit
terraform.tfstate— use remote state (S3 + DynamoDB) - Use workspaces or separate directories per environment
- Pin provider versions to prevent unexpected upgrades
- Tag every resource with project, environment, and managed-by
- Use
terraform fmtto maintain consistent formatting in CI