Agent skill
terraform-patterns
Terraform infrastructure as code patterns and best practices. Use when writing Terraform configurations, creating modules, managing state, or designing IaC architectures.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/terraform-patterns-mindmorass-reflex
SKILL.md
Terraform Patterns
Best practices for Terraform infrastructure as code.
Project Structure
infrastructure/
├── modules/
│ ├── networking/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── README.md
│ ├── compute/
│ └── database/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
│ │ └── backend.tf
│ ├── staging/
│ └── prod/
├── global/
│ ├── iam/
│ └── dns/
└── scripts/
└── init-backend.sh
Module Design
Reusable Module Pattern
hcl
# modules/vpc/variables.tf
variable "name" {
description = "Name prefix for resources"
type = string
}
variable "environment" {
description = "Environment name"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "cidr_block" {
description = "VPC CIDR block"
type = string
default = "10.0.0.0/16"
validation {
condition = can(cidrhost(var.cidr_block, 0))
error_message = "Must be a valid CIDR block."
}
}
variable "availability_zones" {
description = "List of availability zones"
type = list(string)
}
variable "tags" {
description = "Additional tags"
type = map(string)
default = {}
}
hcl
# modules/vpc/main.tf
locals {
common_tags = merge(var.tags, {
Module = "vpc"
Environment = var.environment
ManagedBy = "terraform"
})
}
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(local.common_tags, {
Name = "${var.name}-vpc"
})
}
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.cidr_block, 8, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = merge(local.common_tags, {
Name = "${var.name}-public-${count.index + 1}"
Tier = "public"
})
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.cidr_block, 8, count.index + 10)
availability_zone = var.availability_zones[count.index]
tags = merge(local.common_tags, {
Name = "${var.name}-private-${count.index + 1}"
Tier = "private"
})
}
hcl
# modules/vpc/outputs.tf
output "vpc_id" {
description = "VPC ID"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "List of public subnet IDs"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "List of private subnet IDs"
value = aws_subnet.private[*].id
}
output "vpc_cidr_block" {
description = "VPC CIDR block"
value = aws_vpc.main.cidr_block
}
State Management
Remote Backend Configuration
hcl
# backend.tf
terraform {
backend "s3" {
bucket = "company-terraform-state"
key = "environments/prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
# Assume role for cross-account access
role_arn = "arn:aws:iam::ACCOUNT_ID:role/TerraformStateAccess"
}
}
State Locking Table
hcl
# global/state-backend/main.tf
resource "aws_s3_bucket" "terraform_state" {
bucket = "company-terraform-state"
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
Provider Configuration
Multi-Region Setup
hcl
provider "aws" {
region = var.primary_region
default_tags {
tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "terraform"
}
}
}
provider "aws" {
alias = "dr"
region = var.dr_region
default_tags {
tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "terraform"
}
}
}
Version Constraints
hcl
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.23"
}
}
}
Data Sources and Lookups
hcl
# Look up existing resources
data "aws_vpc" "selected" {
filter {
name = "tag:Environment"
values = [var.environment]
}
}
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
Conditional Resources
hcl
# Create resource only in production
resource "aws_cloudwatch_metric_alarm" "high_cpu" {
count = var.environment == "prod" ? 1 : 0
alarm_name = "${var.name}-high-cpu"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
# Dynamic blocks for optional configurations
resource "aws_security_group" "main" {
name = "${var.name}-sg"
vpc_id = var.vpc_id
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
}
Lifecycle Rules
hcl
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
lifecycle {
create_before_destroy = true
prevent_destroy = var.environment == "prod"
ignore_changes = [
tags["LastModified"],
user_data,
]
}
}
Testing with Terratest
go
// test/vpc_test.go
package test
import (
"testing"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)
func TestVpcModule(t *testing.T) {
terraformOptions := &terraform.Options{
TerraformDir: "../modules/vpc",
Vars: map[string]interface{}{
"name": "test",
"environment": "dev",
"cidr_block": "10.0.0.0/16",
"availability_zones": []string{"us-east-1a", "us-east-1b"},
},
}
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
vpcId := terraform.Output(t, terraformOptions, "vpc_id")
assert.NotEmpty(t, vpcId)
}
CI/CD Integration
yaml
# .github/workflows/terraform.yml
name: Terraform
on:
pull_request:
paths:
- 'infrastructure/**'
push:
branches: [main]
paths:
- 'infrastructure/**'
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.5.0
- name: Terraform Init
run: terraform init
working-directory: infrastructure/environments/${{ github.event.inputs.environment }}
- name: Terraform Plan
run: terraform plan -out=tfplan
working-directory: infrastructure/environments/${{ github.event.inputs.environment }}
- name: Upload Plan
uses: actions/upload-artifact@v4
with:
name: tfplan
path: infrastructure/environments/${{ github.event.inputs.environment }}/tfplan
References
Didn't find tool you were looking for?