home / skills / aj-geddes / useful-ai-prompts / terraform-infrastructure
This skill helps you manage multi-cloud infrastructure with Terraform, enabling modular deployments, remote state, and environment isolation.
npx playbooks add skill aj-geddes/useful-ai-prompts --skill terraform-infrastructureReview the files below or copy the command above to add this skill to your agents.
---
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**
```hcl
# 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**
```hcl
# 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**
```bash
#!/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
```bash
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
```
## Resources
- [Terraform Documentation](https://www.terraform.io/docs/)
- [Terraform AWS Provider](https://registry.terraform.io/providers/hashicorp/aws/latest)
- [Terraform Module Registry](https://registry.terraform.io/)
- [Terraform Best Practices](https://www.terraform.io/docs/language/values/variables#best-practices)
This skill provides opinionated Terraform infrastructure patterns for provisioning and managing cloud resources across AWS, Azure, GCP, and on-prem environments. It focuses on modular design, remote state management, environment workspaces, and repeatable automation to reduce drift and enable safe team workflows. Use it to standardize networking, load balancing, and environment-specific deployments with clear outputs and variables.
The skill supplies Terraform module examples, variable and output conventions, and a deployment script to initialize, validate, plan, apply, or destroy infrastructure per environment. It enforces remote state with locking, workspace isolation, and consistent tagging while exposing easy-to-use outputs (VPC IDs, subnet IDs, ALB DNS/ARN) for downstream automation. The included shell automation streamlines formatting, validation, workspace selection, and execution with environment-specific tfvars.
How do I prevent concurrent state modifications?
Use a remote backend that supports locking (for example S3 with DynamoDB) and enable state locking in your backend configuration.
Can I reuse modules across clouds?
Yes. Design modules to abstract cloud-specific resources behind inputs and create provider-specific implementations or wrappers for multi-cloud reuse.