# Terraform Reviewer

> WHEN: Terraform code review, module structure, state management, security policies WHAT: Module organization + State backend + Security policies + Variable validation + Best practices WHEN NOT: Kubernetes → k8s-reviewer, Docker → docker-reviewer

- Skill: `majiayu000/terraform-reviewer` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add majiayu000/terraform-reviewer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/terraform-reviewer/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/terraform-reviewer

---


# Terraform Reviewer Skill

## Purpose
Reviews Terraform code for module structure, state management, security, and best practices.

## When to Use
- Terraform code review
- Module structure review
- State backend configuration
- Security policy review
- Variable and output review

## Project Detection
- `*.tf` files in project
- `main.tf`, `variables.tf`, `outputs.tf`
- `modules/` directory
- `terraform.tfvars`

## Workflow

### Step 1: Analyze Project
```
**Terraform**: 1.6+
**Provider**: AWS/GCP/Azure
**Backend**: S3/GCS/Azure Blob
**Modules**: Custom + Registry
```

### Step 2: Select Review Areas
**AskUserQuestion:**
```
"Which areas to review?"
Options:
- Full Terraform review (recommended)
- Module structure
- State management
- Security and compliance
- Variable validation
multiSelect: true
```

## Detection Rules

### Module Structure
| Check | Recommendation | Severity |
|-------|----------------|----------|
| All resources in main.tf | Split by resource type | MEDIUM |
| No modules | Extract reusable modules | MEDIUM |
| Hardcoded values | Use variables | HIGH |
| No outputs | Add relevant outputs | MEDIUM |

```
# GOOD: Project structure
terraform/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── terraform.tfvars
│   └── prod/
│       ├── main.tf
│       ├── variables.tf
│       └── terraform.tfvars
├── modules/
│   ├── vpc/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   └── eks/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── README.md
```

```hcl
# BAD: Hardcoded values
resource "aws_instance" "web" {
  ami           = "ami-12345678"
  instance_type = "t3.micro"

  tags = {
    Name = "web-server"
  }
}

# GOOD: Parameterized with variables
variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t3.micro"

  validation {
    condition     = can(regex("^t3\\.", var.instance_type))
    error_message = "Instance type must be t3 family."
  }
}

variable "environment" {
  description = "Environment name"
  type        = string

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = var.instance_type

  tags = merge(local.common_tags, {
    Name = "${var.project}-${var.environment}-web"
  })
}
```

### State Management
| Check | Recommendation | Severity |
|-------|----------------|----------|
| Local state | Use remote backend | CRITICAL |
| No state locking | Enable DynamoDB/GCS lock | HIGH |
| No state encryption | Enable encryption | HIGH |
| Shared state file | Split by environment | MEDIUM |

```hcl
# BAD: Local state (default)
# No backend configuration

# GOOD: Remote backend with locking
terraform {
  backend "s3" {
    bucket         = "mycompany-terraform-state"
    key            = "prod/vpc/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

# For GCP
terraform {
  backend "gcs" {
    bucket  = "mycompany-terraform-state"
    prefix  = "prod/vpc"
  }
}
```

### Security
| Check | Recommendation | Severity |
|-------|----------------|----------|
| Secrets in tfvars | Use secret manager | CRITICAL |
| Public S3 bucket | Set ACL private | CRITICAL |
| Open security group | Restrict CIDR | CRITICAL |
| No encryption | Enable encryption | HIGH |

```hcl
# BAD: Security issues
resource "aws_security_group" "web" {
  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]  # Wide open!
  }
}

resource "aws_s3_bucket" "data" {
  bucket = "my-data-bucket"
  acl    = "public-read"  # Public!
}

# GOOD: Secure configuration
resource "aws_security_group" "web" {
  name        = "${var.project}-web-sg"
  description = "Security group for web servers"
  vpc_id      = var.vpc_id

  ingress {
    description = "HTTPS from load balancer"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    security_groups = [aws_security_group.alb.id]
  }

  egress {
    description = "Allow all outbound"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = local.common_tags
}

resource "aws_s3_bucket" "data" {
  bucket = "${var.project}-${var.environment}-data"
}

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
}

resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
  bucket = aws_s3_bucket.data.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.s3.arn
    }
  }
}
```

### Variable Validation
| Check | Recommendation | Severity |
|-------|----------------|----------|
| No type constraint | Add type | MEDIUM |
| No validation | Add validation block | MEDIUM |
| No description | Add description | LOW |
| Sensitive not marked | Add sensitive = true | HIGH |

```hcl
# GOOD: Well-defined variables
variable "vpc_cidr" {
  description = "CIDR block for VPC"
  type        = string
  default     = "10.0.0.0/16"

  validation {
    condition     = can(cidrnetmask(var.vpc_cidr))
    error_message = "Must be a valid CIDR block."
  }
}

variable "db_password" {
  description = "Database password"
  type        = string
  sensitive   = true  # Won't show in logs

  validation {
    condition     = length(var.db_password) >= 16
    error_message = "Password must be at least 16 characters."
  }
}

variable "allowed_environments" {
  description = "List of allowed environment names"
  type        = list(string)
  default     = ["dev", "staging", "prod"]
}
```

### Resource Naming
| Check | Recommendation | Severity |
|-------|----------------|----------|
| Inconsistent naming | Use naming convention | MEDIUM |
| No tags | Add standard tags | MEDIUM |

```hcl
# GOOD: Consistent naming and tagging
locals {
  name_prefix = "${var.project}-${var.environment}"

  common_tags = {
    Project     = var.project
    Environment = var.environment
    ManagedBy   = "terraform"
    Owner       = var.owner
  }
}

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = merge(local.common_tags, {
    Name = "${local.name_prefix}-vpc"
  })
}
```

## Response Template
```
## Terraform Review Results

**Project**: [name]
**Terraform**: 1.6 | **Provider**: AWS

### Module Structure
| Status | File | Issue |
|--------|------|-------|
| MEDIUM | main.tf | 500+ lines, should split |

### State Management
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | - | Using local state |

### Security
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | security.tf:23 | Security group allows 0.0.0.0/0 |

### Variables
| Status | File | Issue |
|--------|------|-------|
| HIGH | variables.tf | db_password not marked sensitive |

### Recommended Actions
1. [ ] Configure remote state backend with locking
2. [ ] Restrict security group ingress rules
3. [ ] Mark sensitive variables
4. [ ] Split main.tf into logical files
```

## Best Practices
1. **Structure**: Separate by environment, use modules
2. **State**: Remote backend with locking and encryption
3. **Security**: No secrets in code, least privilege
4. **Variables**: Type constraints, validation, descriptions
5. **Naming**: Consistent convention, standard tags

## Integration
- `k8s-reviewer`: EKS/GKE cluster configs
- `infra-security-reviewer`: Compliance checks
- `ci-cd-reviewer`: Terraform in pipelines

