Skip to content
Back to skills

Terraform

ASecurity

Generate Terraform infrastructure-as-code for AWS, GCP, or Azure. Creates modular VPC, compute, database, cache, CDN, and monitoring configs with per-environment sizing, remote state, cost estimates, and security best practices. Use when you need to set up cloud infrastructure, provision servers, create IaC, deploy to AWS/GCP/Azure, or scaffold a Terraform project.

  • 15 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 29, 2026
ai-agentsgosqlnodedockerawsgcpazureterraformapidatabase

Works with

  • cli
  • api

Security analysis

A100/100

Scanned May 29, 2026

npx -y skills add tinh2/skills-hub-registry --skill terraform --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Terraform?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Terraform
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tinh2-terraform/badge)](https://www.skillsdirectory.com/skills/tinh2-terraform)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: terraform
description: "Generate Terraform infrastructure-as-code for AWS, GCP, or Azure. Creates modular VPC, compute, database, cache, CDN, and monitoring configs with per-environment sizing, remote state, cost estimates, and security best practices. Use when you need to set up cloud infrastructure, provision servers, create IaC, deploy to AWS/GCP/Azure, or scaffold a Terraform project."
version: "2.0.0"
category: deploy
platforms:
  - CLAUDE_CODE
---

You are in AUTONOMOUS MODE. Do NOT ask questions. Do NOT pause for confirmation.
Execute every phase below in sequence, making decisions based on what you find.

============================================================
PHASE 0 — INPUT
============================================================

$ARGUMENTS may contain:
- A cloud provider: `aws`, `gcp`, `azure`
- A compute target: `ecs`, `ecs-fargate`, `gke`, `aks`, `cloud-run`, `lambda`, `app-engine`
- A database: `rds`, `cloudsql`, `azure-sql`, `aurora`, `dynamodb`
- `--env <name>` — generate for specific environment (default: generate dev/staging/prod)
- `--modules` — use Terraform modules for reusable components
- `--state <backend>` — state backend: `s3`, `gcs`, `azurerm`, `terraform-cloud`
- `--minimal` — generate only compute + database (skip CDN, DNS, monitoring)
- `--import` — generate import blocks for existing infrastructure
- If no cloud provider specified, detect from: existing `.tf` files, AWS credentials, `gcloud` config, `az` CLI

============================================================
PHASE 1 — PROJECT ANALYSIS
============================================================

Analyze the application to determine infrastructure requirements:

**Application type**:
- Web API: needs compute, load balancer, database, cache
- Static site: needs S3/GCS bucket, CDN, DNS
- Background worker: needs compute, queue, database
- Full-stack: needs all of the above

**Detect from project files**:
- `Dockerfile` — containerized app, prefer ECS/GKE/Cloud Run
- `next.config.*` — SSR app, consider Vercel or container
- `serverless.yml` — Lambda/Cloud Functions
- `prisma/schema.prisma` — read datasource provider for DB engine
- Database ORM config — determine DB engine (postgres, mysql, sqlite, mongodb)
- Redis/cache references — need ElastiCache/Memorystore/Azure Cache

**Existing Terraform**:
- Read any existing `.tf` files to understand current state
- Check for `terraform.tfstate` or remote backend config
- Identify provider and region already in use

============================================================
PHASE 2 — PROJECT STRUCTURE
============================================================

Generate modular Terraform structure:

```
terraform/
  modules/
    networking/
      main.tf
      variables.tf
      outputs.tf
    compute/
      main.tf
      variables.tf
      outputs.tf
    database/
      main.tf
      variables.tf
      outputs.tf
    cache/
      main.tf
      variables.tf
      outputs.tf
    cdn/
      main.tf
      variables.tf
      outputs.tf
    monitoring/
      main.tf
      variables.tf
      outputs.tf
  environments/
    dev/
      main.tf
      variables.tf
      terraform.tfvars
      backend.tf
    staging/
      main.tf
      variables.tf
      terraform.tfvars
      backend.tf
    prod/
      main.tf
      variables.tf
      terraform.tfvars
      backend.tf
  main.tf          # Root module (for simple setups)
  variables.tf
  outputs.tf
  providers.tf
  versions.tf
```

If `--modules` is not set and project is simple, use flat structure:
```
terraform/
  main.tf
  variables.tf
  outputs.tf
  providers.tf
  versions.tf
  terraform.tfvars.example
```

============================================================
PHASE 3 — PROVIDER AND STATE CONFIGURATION
============================================================

**`versions.tf`**:
```hcl
terraform {
  required_version = ">= 1.7.0"

  required_providers {
    aws = {  # or google, azurerm
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
```

**`providers.tf`**:
```hcl
provider "aws" {
  region = var.aws_region

  default_tags {
    tags = {
      Project     = var.project_name
      Environment = var.environment
      ManagedBy   = "terraform"
    }
  }
}
```

**`backend.tf`** (per environment):
- **AWS S3**:
  ```hcl
  terraform {
    backend "s3" {
      bucket         = "{project}-terraform-state"
      key            = "{env}/terraform.tfstate"
      region         = "us-east-1"
      encrypt        = true
      dynamodb_table = "{project}-terraform-locks"
    }
  }
  ```
- **GCP GCS**:
  ```hcl
  terraform {
    backend "gcs" {
      bucket = "{project}-terraform-state"
      prefix = "{env}"
    }
  }
  ```
- **Azure**:
  ```hcl
  terraform {
    backend "azurerm" {
      resource_group_name  = "{project}-terraform-rg"
      storage_account_name = "{project}tfstate"
      container_name       = "tfstate"
      key                  = "{env}.terraform.tfstate"
    }
  }
  ```

============================================================
PHASE 4 — NETWORKING MODULE
============================================================

**AWS VPC**:
- VPC with /16 CIDR (e.g., 10.0.0.0/16)
- 3 public subnets across AZs (for ALB)
- 3 private subnets across AZs (for compute, DB)
- NAT Gateway (single for dev, per-AZ for prod)
- Internet Gateway
- Route tables (public and private)
- VPC Flow Logs (prod only)

**GCP**:
- VPC network with custom subnets
- Cloud Router + Cloud NAT
- Firewall rules (deny all ingress by default, allow from LB)

**Azure**:
- Virtual Network with subnets
- Network Security Groups
- NAT Gateway

Always output: `vpc_id`, `public_subnet_ids`, `private_subnet_ids`

============================================================
PHASE 5 — COMPUTE MODULE
============================================================

**AWS ECS Fargate** (default for containerized apps):
```hcl
resource "aws_ecs_cluster" "main" {
  name = "${var.project_name}-${var.environment}"
  setting {
    name  = "containerInsights"
    value = "enabled"
  }
}

resource "aws_ecs_task_definition" "app" {
  family                   = "${var.project_name}-${var.environment}"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = var.task_cpu
  memory                   = var.task_memory
  execution_role_arn       = aws_iam_role.ecs_execution.arn
  task_role_arn            = aws_iam_role.ecs_task.arn
  # container_definitions from template
}

resource "aws_ecs_service" "app" {
  name            = "${var.project_name}-${var.environment}"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.app.arn
  desired_count   = var.desired_count
  launch_type     = "FARGATE"

  network_configuration {
    subnets         = var.private_subnet_ids
    security_groups = [aws_security_group.ecs.id]
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.app.arn
    container_name   = var.project_name
    container_port   = var.container_port
  }
}
```

- Application Load Balancer with HTTPS listener
- Auto-scaling policies (CPU and memory targets)
- Security groups (ALB -> ECS only)
- IAM roles (execution role for ECR pull, task role for app permissions)

**GCP Cloud Run**:
- `google_cloud_run_v2_service` with auto-scaling
- IAM for public access or authenticated only
- Custom domain mapping

**Azure Container Apps / AKS**:
- Container App Environment or AKS cluster
- Managed identity for secrets access

Include environment-specific sizing:
- **dev**: minimal (256 CPU, 512 MB, 1 task)
- **staging**: moderate (512 CPU, 1 GB, 2 tasks)
- **prod**: production (1024 CPU, 2 GB, 3+ tasks, auto-scaling)

============================================================
PHASE 6 — DATABASE MODULE
============================================================

**AWS RDS**:
```hcl
resource "aws_db_instance" "main" {
  identifier     = "${var.project_name}-${var.environment}"
  engine         = var.db_engine  # "postgres" or "mysql"
  engine_version = var.db_engine_version
  instance_class = var.db_instance_class

  allocated_storage     = var.db_storage
  max_allocated_storage = var.db_max_storage  # auto-scaling

  db_name  = var.db_name
  username = var.db_username
  password = var.db_password  # from secrets manager

  vpc_security_group_ids = [aws_security_group.db.id]
  db_subnet_group_name   = aws_db_subnet_group.main.name

  multi_az               = var.environment == "prod"
  backup_retention_period = var.environment == "prod" ? 30 : 7
  deletion_protection    = var.environment == "prod"
  skip_final_snapshot    = var.environment != "prod"

  storage_encrypted = true

  performance_insights_enabled = var.environment == "prod"
}
```

- DB subnet group in private subnets
- Security group (allow from compute SG only)
- Parameter group with optimized settings
- Automated backups with retention policy

**GCP Cloud SQL**: equivalent with `google_sql_database_instance`
**Azure SQL**: equivalent with `azurerm_mssql_server`

Environment sizing:
- **dev**: `db.t4g.micro` / smallest tier, single-AZ
- **staging**: `db.t4g.small`, single-AZ
- **prod**: `db.r6g.large`, multi-AZ, performance insights, 30-day backups

============================================================
PHASE 7 — CACHE, CDN, DNS MODULES (if not --minimal)
============================================================

**Cache** (if Redis/cache detected):
- AWS ElastiCache Redis cluster
- Single node for dev, replication group for prod
- Security group (allow from compute only)

**CDN** (if web application):
- CloudFront distribution with S3 origin or ALB origin
- Cache behaviors (static assets: 1y, API: no-cache, HTML: 5m)
- Custom error responses (403 -> /index.html for SPAs)

**DNS** (if domain configured):
- Route53 hosted zone
- A record aliased to CloudFront or ALB
- ACM certificate with DNS validation

============================================================
PHASE 8 — MONITORING MODULE
============================================================

- CloudWatch alarms for: ECS CPU, ECS memory, RDS connections, ALB 5xx rate
- CloudWatch dashboard with key metrics
- SNS topic for alarm notifications
- Log groups with retention policies (dev: 7d, staging: 30d, prod: 90d)

============================================================
PHASE 9 — VARIABLES AND OUTPUTS
============================================================

**`variables.tf`** — define all inputs with descriptions, types, defaults, and validation:
```hcl
variable "project_name" {
  description = "Name of the project, used in resource naming"
  type        = string
  validation {
    condition     = can(regex("^[a-z0-9-]+$", var.project_name))
    error_message = "Project name must be lowercase alphanumeric with hyphens."
  }
}

variable "environment" {
  description = "Deployment environment"
  type        = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}
```

**`outputs.tf`** — expose key values:
```hcl
output "app_url" {
  description = "Application URL"
  value       = "https://${var.domain}"
}

output "database_endpoint" {
  description = "Database connection endpoint"
  value       = aws_db_instance.main.endpoint
  sensitive   = true
}
```

**`terraform.tfvars.example`** — example values for each variable (never real secrets):
```hcl
project_name = "my-app"
environment  = "dev"
aws_region   = "us-east-1"
# db_password = "REPLACE_ME"  # Use secrets manager
```

============================================================
PHASE 10 — COST ANNOTATIONS
============================================================

Add cost estimate comments to each resource:
```hcl
# Cost estimate (us-east-1):
#   dev:     ~$15/mo (t4g.micro, single-AZ, 20GB)
#   staging: ~$35/mo (t4g.small, single-AZ, 50GB)
#   prod:    ~$200/mo (r6g.large, multi-AZ, 100GB, PIOPS)
resource "aws_db_instance" "main" { ... }
```


============================================================
SELF-HEALING VALIDATION (max 2 iterations)
============================================================

After completing deployment/infrastructure changes, validate:

1. Verify all generated files are syntactically valid (YAML, JSON, HCL, Dockerfile).
2. Run validation commands if available (terraform validate, docker build --check, kubectl dry-run).
3. Verify no secrets, credentials, or sensitive values are hardcoded.
4. If validation fails, diagnose and fix the specific syntax or config error.
5. Repeat up to 2 iterations.

IF STILL FAILING after 2 iterations:
- Document what failed and the exact error
- Include partial output if available

============================================================
OUTPUT
============================================================

```
## Terraform Configuration Generated

### Structure
{tree of generated files}

### Resources by Environment
| Resource | Dev | Staging | Prod |
|----------|-----|---------|------|
| Compute | {spec} | {spec} | {spec} |
| Database | {spec} | {spec} | {spec} |
| Cache | — | {spec} | {spec} |

### Estimated Monthly Cost
| Environment | Estimate |
|-------------|----------|
| Dev | ~${X}/mo |
| Staging | ~${X}/mo |
| Prod | ~${X}/mo |

### Commands
terraform init
terraform plan -var-file="environments/dev/terraform.tfvars"
terraform apply -var-file="environments/dev/terraform.tfvars"
```

============================================================
NEXT STEPS
============================================================

1. Create the state backend (S3 bucket + DynamoDB table) before running `terraform init`
2. Set sensitive variables via environment variables or Terraform Cloud
3. Start with dev environment, validate, then promote to staging and prod
4. Set up CI/CD to run `terraform plan` on PRs and `terraform apply` on merge
5. Enable Terraform Cloud or Spacelift for team collaboration and state locking


============================================================
SELF-EVOLUTION TELEMETRY
============================================================

After producing output, record execution metadata for the /evolve pipeline.

Check if a project memory directory exists:
- Look for the project path in `~/.claude/projects/`
- If found, append to `skill-telemetry.md` in that memory directory

Entry format:
```
### /terraform — {{YYYY-MM-DD}}
- Outcome: {{SUCCESS | PARTIAL | FAILED}}
- Self-healed: {{yes — what was healed | no}}
- Iterations used: {{N}} / {{N max}}
- Bottleneck: {{phase that struggled or "none"}}
- Suggestion: {{one-line improvement idea for /evolve, or "none"}}
```

Only log if the memory directory exists. Skip silently if not found.
Keep entries concise — /evolve will parse these for skill improvement signals.

============================================================
DO NOT
============================================================

- Do NOT hardcode secrets, passwords, or API keys in `.tf` or `.tfvars` files
- Do NOT use `terraform apply -auto-approve` in documentation — always review plans
- Do NOT create resources without tags — use default_tags on the provider
- Do NOT use overly permissive IAM policies (`*` actions or resources)
- Do NOT skip `deletion_protection` on production databases
- Do NOT create public subnets for databases or caches
- Do NOT use `latest` AMI IDs — pin to specific versions or use data sources
- Do NOT generate resources for services not needed by the application
- Do NOT overwrite existing Terraform files — read and extend them
- Do NOT use deprecated resource types or provider syntax
- Do NOT create NAT Gateways per-AZ for dev environments (cost optimization)
- Do NOT skip remote state configuration — local state is not suitable for teams

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…