Skill
terraform-skills
Write Terraform infrastructure-as-code — modules, providers, state management, workspaces, and security. Use when the user mentions "Terraform", "IaC", "infrastructure as code", "cloud provisioning", or needs to manage cloud resources declaratively.
From project-orchestratorInstall
1
Run in your terminal$
npx claudepluginhub vivekmano27/agent-orchestrator --plugin project-orchestratorTool Access
This skill is limited to using the following tools:
ReadWriteEditBashGrepGlob
Skill Content
Terraform Skills
Output Structure
Every Terraform module must produce this file layout. Do not put all resources in a single file.
infrastructure/
├── main.tf # Provider config, backend, module calls
├── variables.tf # Root-level input variables
├── outputs.tf # Root-level outputs
├── terraform.tfvars # Default values (NEVER commit secrets here)
├── environments/
│ ├── dev.tfvars
│ ├── staging.tfvars
│ └── prod.tfvars
└── modules/
└── <module-name>/
├── main.tf # Resources
├── variables.tf # Module inputs with validation blocks
├── outputs.tf # Module outputs
└── versions.tf # Required providers and terraform version
State Backend Configuration
Always configure remote state with locking. Never use local state for shared infrastructure.
# main.tf — backend config
terraform {
required_version = ">= 1.5.0"
backend "s3" {
bucket = "myproject-terraform-state"
key = "infrastructure/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock"
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "terraform"
}
}
}
State Lock Table (bootstrap this manually or via a separate config)
resource "aws_dynamodb_table" "terraform_lock" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
VPC + Subnets Module (Reference Pattern)
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = { Name = "${var.project}-${var.environment}-vpc" }
}
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = var.azs[count.index]
map_public_ip_on_launch = true
tags = { Name = "${var.project}-public-${var.azs[count.index]}" }
}
resource "aws_subnet" "private" {
count = length(var.private_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnet_cidrs[count.index]
availability_zone = var.azs[count.index]
tags = { Name = "${var.project}-private-${var.azs[count.index]}" }
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = { Name = "${var.project}-igw" }
}
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}-public-rt" }
}
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# modules/vpc/variables.tf
variable "project" {
type = string
description = "Project name, used in resource naming"
}
variable "environment" {
type = string
description = "Environment (dev, staging, prod)"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "cidr_block" {
type = string
default = "10.0.0.0/16"
description = "VPC CIDR block"
validation {
condition = can(cidrhost(var.cidr_block, 0))
error_message = "cidr_block must be a valid CIDR notation (e.g., 10.0.0.0/16)."
}
}
variable "public_subnet_cidrs" {
type = list(string)
description = "CIDR blocks for public subnets (one per AZ)"
validation {
condition = length(var.public_subnet_cidrs) >= 2
error_message = "At least 2 public subnets required for high availability."
}
}
variable "private_subnet_cidrs" {
type = list(string)
description = "CIDR blocks for private subnets (one per AZ)"
validation {
condition = length(var.private_subnet_cidrs) >= 2
error_message = "At least 2 private subnets required for high availability."
}
}
variable "azs" {
type = list(string)
description = "Availability zones to use"
validation {
condition = length(var.azs) >= 2
error_message = "At least 2 AZs required for high availability."
}
}
# modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
description = "VPC ID"
}
output "public_subnet_ids" {
value = aws_subnet.public[*].id
description = "List of public subnet IDs"
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
description = "List of private subnet IDs"
}
output "vpc_cidr_block" {
value = aws_vpc.main.cidr_block
description = "VPC CIDR block for security group rules"
}
Constraints
- Every variable must have a
description. Variables without descriptions causeterraform-docsto produce useless output. - Use
validationblocks for any variable with a constrained domain (environment names, CIDR blocks, instance types, region names). This catches typos atplantime instead ofapplytime. - Never hardcode AMI IDs, account IDs, or region names in resource blocks. Use variables or data sources (
data.aws_ami,data.aws_caller_identity). - Tag every resource with at least
Project,Environment, andManagedBy = "terraform". Use the providerdefault_tagsblock shown above so individual resources inherit automatically. - Pin provider versions with
~>pessimistic constraint (e.g.,~> 5.0). Never use>=without an upper bound in production. - Never output secrets. If a resource produces a sensitive value (e.g., RDS password), mark the output with
sensitive = true.
Workflow Commands Reference
# Initialize (download providers, configure backend)
terraform init
# Format all .tf files (enforced in CI)
terraform fmt -recursive
# Validate syntax and types
terraform validate
# Plan against a specific environment
terraform plan -var-file=environments/prod.tfvars -out=plan.tfplan
# Apply a saved plan (never apply without a plan file in production)
terraform apply plan.tfplan
# Import existing resources into state
terraform import aws_vpc.main vpc-abc123
# Destroy (requires explicit approval)
terraform destroy -var-file=environments/dev.tfvars
Similar Skills
Stats
Parent Repo Stars0
Parent Repo Forks0
Last CommitMar 15, 2026