askill
terraform-reviewer

terraform-reviewerSafety 90Repository

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

0 stars
1.2k downloads
Updated 2/5/2026

Package Files

Loading files...
SKILL.md

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

CheckRecommendationSeverity
All resources in main.tfSplit by resource typeMEDIUM
No modulesExtract reusable modulesMEDIUM
Hardcoded valuesUse variablesHIGH
No outputsAdd relevant outputsMEDIUM
# 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
# 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

CheckRecommendationSeverity
Local stateUse remote backendCRITICAL
No state lockingEnable DynamoDB/GCS lockHIGH
No state encryptionEnable encryptionHIGH
Shared state fileSplit by environmentMEDIUM
# 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

CheckRecommendationSeverity
Secrets in tfvarsUse secret managerCRITICAL
Public S3 bucketSet ACL privateCRITICAL
Open security groupRestrict CIDRCRITICAL
No encryptionEnable encryptionHIGH
# 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

CheckRecommendationSeverity
No type constraintAdd typeMEDIUM
No validationAdd validation blockMEDIUM
No descriptionAdd descriptionLOW
Sensitive not markedAdd sensitive = trueHIGH
# 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

CheckRecommendationSeverity
Inconsistent namingUse naming conventionMEDIUM
No tagsAdd standard tagsMEDIUM
# 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

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/10/2026

A comprehensive and highly actionable skill for reviewing Terraform code. It provides clear detection rules, severity levels, and 'Good vs Bad' examples across multiple domains including security, state management, and module structure.

90
98
95
95
98

Metadata

Licenseunknown
Version-
Updated2/5/2026
Publishermajiayu000

Tags

ci-cddatabasegithub-actionssecurity