Terraform Cheatsheet for AWS
Terraform is the industry standard for Infrastructure as Code (IaC). This cheatsheet provides a quick reference for essential commands, state management, and common AWS resource patterns.
1. Essential CLI Commands
Workflow
bash
# Initialize working directory (do this first!)
terraform init
# Check formatting
terraform fmt -recursive
# Validate configuration syntax
terraform validate
# Plan changes (dry run)
terraform plan -out=tfplan
# Apply changes
terraform apply tfplan
# OR auto-approve (use with caution)
terraform apply -auto-approve
# Destroy infrastructure
terraform destroyState Management
Managing state is critical for teamwork and consistency.
bash
# List all resources in state
terraform state list
# Show details of a specific resource
terraform state show aws_s3_bucket.my_bucket
# Move a resource (rename in state without destroying)
terraform state mv aws_instance.old aws_instance.new
# Remove a resource from state (stop tracking it)
terraform state rm aws_instance.legacy
# Import existing AWS resource into state
terraform import aws_s3_bucket.existing_bucket my-bucket-nameDebugging
bash
# Enable verbose logging (TRACE, DEBUG, INFO, WARN, ERROR)
export TF_LOG=DEBUG
# Output logs to file
export TF_LOG_PATH=./terraform.log2. AWS Provider Configuration
Configure the AWS provider with best practices for multi-region or multi-profile setups.
hcl
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
required_version = ">= 1.5.0"
}
provider "aws" {
region = "us-east-1"
profile = "my-profile" # ~/.aws/credentials profile
default_tags {
tags = {
Environment = "Production"
ManagedBy = "Terraform"
}
}
}
# Alias for secondary region (e.g., for ACM in us-east-1)
provider "aws" {
alias = "us-east-1"
region = "us-east-1"
}3. Core AWS Resources
VPC & Networking
hcl
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "main-vpc"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true
availability_zone = "us-west-2a"
}
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
}Security Group
Best Practice
Always use name_prefix instead of name to allow Terraform to replace the resource with zero downtime (create before destroy).
hcl
resource "aws_security_group" "web" {
name_prefix = "web-sg-"
vpc_id = aws_vpc.main.id
# Inbound HTTP
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Outbound All
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
}EC2 Instance
hcl
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
python3 -m http.server 80 &
EOF
tags = {
Name = "web-server"
}
}S3 Bucket (Private)
hcl
resource "aws_s3_bucket" "data" {
bucket = "my-unique-bucket-name-123"
}
# Block all public access (Safety First!)
resource "aws_s3_bucket_public_access_block" "data" {
bucket = aws_s3_bucket.data.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# Enable versioning
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration {
status = "Enabled"
}
}4. Variables & Outputs
Input Variables (variables.tf)
hcl
variable "environment" {
description = "Deployment environment (dev, staging, prod)"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_count" {
type = number
default = 1
}Outputs (outputs.tf)
hcl
output "web_url" {
description = "Public URL of the web server"
value = "http://${aws_instance.web.public_ip}"
}5. Best Practices Checklist
Production Readiness
Before deploying to production, ensure you check these items.
- [ ] Remote State: Use S3 backend with DynamoDB locking. Never commit
terraform.tfstateto git. - [ ] Versioning: Pin provider and Terraform versions.
- [ ] Structure: Separate
main.tf,variables.tf, andoutputs.tf. - [ ] Secrets: Never hardcode secrets. Use AWS Secrets Manager or environment variables (
TF_VAR_db_password). - [ ] Formatting: Always run
terraform fmt. - [ ] Modules: Use modules for reusable components (e.g., standard VPC setup).
- [ ] Taint: Don't manually modifying resources in AWS console; Terraform will blindly revert them.
Remote Backend Example
hcl
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "prod/app.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}