Smithery Logo
MCPsSkillsDocsPricing
Login
NewFlame, an assistant that learns and improves. Available onTelegramSlack
    Dexploarer

    terraform-module-builder

    Dexploarer/terraform-module-builder
    DevOps
    4

    About

    SKILL.md

    Install

    • Telegram
      Telegram
    • Slack
      Slack
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    • Download skill
    ├─
    ├─
    └─
    Smithery Logo

    Give agents more agency

    Resources

    DocumentationPrivacy PolicySystem Status

    Company

    PricingAboutBlog

    Connect

    © 2026 Smithery. All rights reserved.

    About

    Generates reusable Terraform modules with best practices for AWS, Azure, GCP infrastructure as code...

    SKILL.md

    Terraform Module Builder

    Generates production-ready, reusable Terraform modules with best practices for multi-cloud infrastructure as code.

    When to Use

    • "Create Terraform module"
    • "Generate infrastructure module"
    • "Setup Terraform for AWS/Azure/GCP"
    • "Create reusable IaC module"
    • "Generate Terraform boilerplate"

    Instructions

    1. Module Structure

    terraform-aws-vpc/
    ├── main.tf           # Main resources
    ├── variables.tf      # Input variables
    ├── outputs.tf        # Output values
    ├── versions.tf       # Provider versions
    ├── README.md         # Documentation
    ├── examples/         # Usage examples
    │   └── complete/
    │       ├── main.tf
    │       └── variables.tf
    └── tests/            # Terratest
        └── vpc_test.go
    

    2. AWS VPC Module Example

    main.tf:

    # main.tf
    locals {
      name = var.name != "" ? var.name : "${var.environment}-vpc"
    
      common_tags = merge(
        var.tags,
        {
          Environment = var.environment
          ManagedBy   = "Terraform"
          Module      = "terraform-aws-vpc"
        }
      )
    }
    
    resource "aws_vpc" "this" {
      cidr_block           = var.vpc_cidr
      enable_dns_hostnames = var.enable_dns_hostnames
      enable_dns_support   = var.enable_dns_support
    
      tags = merge(
        local.common_tags,
        {
          Name = local.name
        }
      )
    }
    
    resource "aws_subnet" "public" {
      count = length(var.public_subnet_cidrs)
    
      vpc_id                  = aws_vpc.this.id
      cidr_block              = var.public_subnet_cidrs[count.index]
      availability_zone       = var.availability_zones[count.index]
      map_public_ip_on_launch = true
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-public-${var.availability_zones[count.index]}"
          Type = "public"
        }
      )
    }
    
    resource "aws_subnet" "private" {
      count = length(var.private_subnet_cidrs)
    
      vpc_id            = aws_vpc.this.id
      cidr_block        = var.private_subnet_cidrs[count.index]
      availability_zone = var.availability_zones[count.index]
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-private-${var.availability_zones[count.index]}"
          Type = "private"
        }
      )
    }
    
    resource "aws_internet_gateway" "this" {
      count = length(var.public_subnet_cidrs) > 0 ? 1 : 0
    
      vpc_id = aws_vpc.this.id
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-igw"
        }
      )
    }
    
    resource "aws_eip" "nat" {
      count = var.enable_nat_gateway ? length(var.availability_zones) : 0
    
      domain = "vpc"
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-nat-${var.availability_zones[count.index]}"
        }
      )
    
      depends_on = [aws_internet_gateway.this]
    }
    
    resource "aws_nat_gateway" "this" {
      count = var.enable_nat_gateway ? length(var.availability_zones) : 0
    
      allocation_id = aws_eip.nat[count.index].id
      subnet_id     = aws_subnet.public[count.index].id
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-nat-${var.availability_zones[count.index]}"
        }
      )
    
      depends_on = [aws_internet_gateway.this]
    }
    
    resource "aws_route_table" "public" {
      count = length(var.public_subnet_cidrs) > 0 ? 1 : 0
    
      vpc_id = aws_vpc.this.id
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-public"
        }
      )
    }
    
    resource "aws_route" "public_internet_gateway" {
      count = length(var.public_subnet_cidrs) > 0 ? 1 : 0
    
      route_table_id         = aws_route_table.public[0].id
      destination_cidr_block = "0.0.0.0/0"
      gateway_id             = aws_internet_gateway.this[0].id
    
      timeouts {
        create = "5m"
      }
    }
    
    resource "aws_route_table_association" "public" {
      count = length(var.public_subnet_cidrs)
    
      subnet_id      = aws_subnet.public[count.index].id
      route_table_id = aws_route_table.public[0].id
    }
    
    resource "aws_route_table" "private" {
      count = length(var.private_subnet_cidrs)
    
      vpc_id = aws_vpc.this.id
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-private-${var.availability_zones[count.index]}"
        }
      )
    }
    
    resource "aws_route" "private_nat_gateway" {
      count = var.enable_nat_gateway ? length(var.private_subnet_cidrs) : 0
    
      route_table_id         = aws_route_table.private[count.index].id
      destination_cidr_block = "0.0.0.0/0"
      nat_gateway_id         = aws_nat_gateway.this[count.index].id
    
      timeouts {
        create = "5m"
      }
    }
    
    resource "aws_route_table_association" "private" {
      count = length(var.private_subnet_cidrs)
    
      subnet_id      = aws_subnet.private[count.index].id
      route_table_id = aws_route_table.private[count.index].id
    }
    
    resource "aws_flow_log" "this" {
      count = var.enable_flow_logs ? 1 : 0
    
      iam_role_arn    = aws_iam_role.flow_logs[0].arn
      log_destination = aws_cloudwatch_log_group.flow_logs[0].arn
      traffic_type    = "ALL"
      vpc_id          = aws_vpc.this.id
    
      tags = merge(
        local.common_tags,
        {
          Name = "${local.name}-flow-logs"
        }
      )
    }
    
    resource "aws_cloudwatch_log_group" "flow_logs" {
      count = var.enable_flow_logs ? 1 : 0
    
      name              = "/aws/vpc/${local.name}"
      retention_in_days = var.flow_logs_retention_days
    
      tags = local.common_tags
    }
    
    resource "aws_iam_role" "flow_logs" {
      count = var.enable_flow_logs ? 1 : 0
    
      name = "${local.name}-flow-logs"
    
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Action = "sts:AssumeRole"
            Effect = "Allow"
            Principal = {
              Service = "vpc-flow-logs.amazonaws.com"
            }
          }
        ]
      })
    
      tags = local.common_tags
    }
    
    resource "aws_iam_role_policy" "flow_logs" {
      count = var.enable_flow_logs ? 1 : 0
    
      name = "flow-logs"
      role = aws_iam_role.flow_logs[0].id
    
      policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Action = [
              "logs:CreateLogGroup",
              "logs:CreateLogStream",
              "logs:PutLogEvents",
              "logs:DescribeLogGroups",
              "logs:DescribeLogStreams"
            ]
            Effect   = "Allow"
            Resource = "*"
          }
        ]
      })
    }
    

    variables.tf:

    # variables.tf
    variable "name" {
      description = "Name to be used on all resources as prefix"
      type        = string
      default     = ""
    }
    
    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 "vpc_cidr" {
      description = "CIDR block for VPC"
      type        = string
      default     = "10.0.0.0/16"
    
      validation {
        condition     = can(cidrhost(var.vpc_cidr, 0))
        error_message = "VPC CIDR must be a valid IPv4 CIDR block."
      }
    }
    
    variable "availability_zones" {
      description = "List of availability zones"
      type        = list(string)
    }
    
    variable "public_subnet_cidrs" {
      description = "CIDR blocks for public subnets"
      type        = list(string)
      default     = []
    }
    
    variable "private_subnet_cidrs" {
      description = "CIDR blocks for private subnets"
      type        = list(string)
      default     = []
    }
    
    variable "enable_dns_hostnames" {
      description = "Enable DNS hostnames in VPC"
      type        = bool
      default     = true
    }
    
    variable "enable_dns_support" {
      description = "Enable DNS support in VPC"
      type        = bool
      default     = true
    }
    
    variable "enable_nat_gateway" {
      description = "Enable NAT Gateway for private subnets"
      type        = bool
      default     = true
    }
    
    variable "enable_flow_logs" {
      description = "Enable VPC Flow Logs"
      type        = bool
      default     = false
    }
    
    variable "flow_logs_retention_days" {
      description = "Flow logs retention in days"
      type        = number
      default     = 7
    }
    
    variable "tags" {
      description = "Additional tags for all resources"
      type        = map(string)
      default     = {}
    }
    

    outputs.tf:

    # outputs.tf
    output "vpc_id" {
      description = "ID of the VPC"
      value       = aws_vpc.this.id
    }
    
    output "vpc_cidr" {
      description = "CIDR block of the VPC"
      value       = aws_vpc.this.cidr_block
    }
    
    output "public_subnet_ids" {
      description = "IDs of public subnets"
      value       = aws_subnet.public[*].id
    }
    
    output "private_subnet_ids" {
      description = "IDs of private subnets"
      value       = aws_subnet.private[*].id
    }
    
    output "nat_gateway_ids" {
      description = "IDs of NAT Gateways"
      value       = aws_nat_gateway.this[*].id
    }
    
    output "internet_gateway_id" {
      description = "ID of Internet Gateway"
      value       = try(aws_internet_gateway.this[0].id, null)
    }
    
    output "public_route_table_ids" {
      description = "IDs of public route tables"
      value       = aws_route_table.public[*].id
    }
    
    output "private_route_table_ids" {
      description = "IDs of private route tables"
      value       = aws_route_table.private[*].id
    }
    

    versions.tf:

    # versions.tf
    terraform {
      required_version = ">= 1.0"
    
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = ">= 5.0"
        }
      }
    }
    

    3. Usage Example

    examples/complete/main.tf:

    provider "aws" {
      region = "us-west-2"
    }
    
    module "vpc" {
      source = "../../"
    
      name        = "my-app"
      environment = "production"
    
      vpc_cidr           = "10.0.0.0/16"
      availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
    
      public_subnet_cidrs = [
        "10.0.1.0/24",
        "10.0.2.0/24",
        "10.0.3.0/24",
      ]
    
      private_subnet_cidrs = [
        "10.0.11.0/24",
        "10.0.12.0/24",
        "10.0.13.0/24",
      ]
    
      enable_nat_gateway = true
      enable_flow_logs   = true
    
      tags = {
        Project = "MyApp"
        Owner   = "Platform Team"
      }
    }
    
    output "vpc_id" {
      value = module.vpc.vpc_id
    }
    

    4. Multi-Cloud: Azure Module

    main.tf (Azure):

    resource "azurerm_resource_group" "this" {
      name     = "${var.name}-rg"
      location = var.location
    
      tags = var.tags
    }
    
    resource "azurerm_virtual_network" "this" {
      name                = "${var.name}-vnet"
      resource_group_name = azurerm_resource_group.this.name
      location            = azurerm_resource_group.this.location
      address_space       = [var.vnet_cidr]
    
      tags = var.tags
    }
    
    resource "azurerm_subnet" "public" {
      count = length(var.public_subnet_cidrs)
    
      name                 = "${var.name}-public-${count.index + 1}"
      resource_group_name  = azurerm_resource_group.this.name
      virtual_network_name = azurerm_virtual_network.this.name
      address_prefixes     = [var.public_subnet_cidrs[count.index]]
    }
    
    resource "azurerm_subnet" "private" {
      count = length(var.private_subnet_cidrs)
    
      name                 = "${var.name}-private-${count.index + 1}"
      resource_group_name  = azurerm_resource_group.this.name
      virtual_network_name = azurerm_virtual_network.this.name
      address_prefixes     = [var.private_subnet_cidrs[count.index]]
    }
    
    resource "azurerm_network_security_group" "this" {
      name                = "${var.name}-nsg"
      location            = azurerm_resource_group.this.location
      resource_group_name = azurerm_resource_group.this.name
    
      tags = var.tags
    }
    

    5. State Management

    backend.tf:

    # backend.tf - S3 backend
    terraform {
      backend "s3" {
        bucket         = "my-terraform-state"
        key            = "vpc/terraform.tfstate"
        region         = "us-west-2"
        encrypt        = true
        dynamodb_table = "terraform-locks"
      }
    }
    

    Remote state (Azure):

    terraform {
      backend "azurerm" {
        resource_group_name  = "terraform-state-rg"
        storage_account_name = "tfstate"
        container_name       = "tfstate"
        key                  = "vpc.terraform.tfstate"
      }
    }
    

    6. Testing with Terratest

    tests/vpc_test.go:

    package test
    
    import (
        "testing"
        "github.com/gruntwork-io/terratest/modules/terraform"
        "github.com/stretchr/testify/assert"
    )
    
    func TestVPCModule(t *testing.T) {
        t.Parallel()
    
        terraformOptions := &terraform.Options{
            TerraformDir: "../examples/complete",
            Vars: map[string]interface{}{
                "environment": "test",
            },
        }
    
        defer terraform.Destroy(t, terraformOptions)
    
        terraform.InitAndApply(t, terraformOptions)
    
        vpcID := terraform.Output(t, terraformOptions, "vpc_id")
        assert.NotEmpty(t, vpcID)
    
        publicSubnets := terraform.OutputList(t, terraformOptions, "public_subnet_ids")
        assert.Equal(t, 3, len(publicSubnets))
    }
    

    7. Documentation (README.md)

    # AWS VPC Terraform Module
    
    Creates a VPC with public and private subnets across multiple availability zones.
    
    ## Features
    
    - Multi-AZ deployment
    - Public and private subnets
    - NAT Gateways (optional)
    - VPC Flow Logs (optional)
    - Customizable CIDR blocks
    - Comprehensive tagging
    
    ## Usage
    
    \`\`\`hcl
    module "vpc" {
      source = "github.com/your-org/terraform-aws-vpc"
    
      name        = "my-vpc"
      environment = "production"
    
      vpc_cidr           = "10.0.0.0/16"
      availability_zones = ["us-west-2a", "us-west-2b"]
    
      public_subnet_cidrs  = ["10.0.1.0/24", "10.0.2.0/24"]
      private_subnet_cidrs = ["10.0.11.0/24", "10.0.12.0/24"]
    
      enable_nat_gateway = true
      enable_flow_logs   = true
    
      tags = {
        Project = "MyApp"
      }
    }
    \`\`\`
    
    ## Inputs
    
    | Name | Description | Type | Default | Required |
    |------|-------------|------|---------|----------|
    | name | VPC name | string | - | yes |
    | environment | Environment | string | - | yes |
    | vpc_cidr | VPC CIDR | string | "10.0.0.0/16" | no |
    | availability_zones | AZs | list(string) | - | yes |
    | enable_nat_gateway | Enable NAT | bool | true | no |
    
    ## Outputs
    
    | Name | Description |
    |------|-------------|
    | vpc_id | VPC ID |
    | public_subnet_ids | Public subnet IDs |
    | private_subnet_ids | Private subnet IDs |
    
    ## Requirements
    
    | Name | Version |
    |------|---------|
    | terraform | >= 1.0 |
    | aws | >= 5.0 |
    

    Best Practices

    DO:

    • Use semantic versioning
    • Document all variables
    • Provide examples
    • Add validation rules
    • Use locals for DRY code
    • Tag all resources
    • Use remote state
    • Write tests
    • Follow naming conventions

    DON'T:

    • Hardcode values
    • Skip validation
    • Use default values in production
    • Ignore dependencies
    • Skip documentation
    • Commit .tfstate files
    • Use latest provider versions
    • Forget outputs

    Checklist

    • Module structure created
    • Variables defined with validation
    • Resources created
    • Outputs defined
    • Documentation written
    • Examples provided
    • Tests written
    • Versioned and tagged
    Recommended Servers
    OpenZeppelin
    OpenZeppelin
    Microsoft Learn MCP
    Microsoft Learn MCP
    Codeinterpreter
    Codeinterpreter
    Repository
    dexploarer/claudius-skills
    Files