スキル一覧に戻る
lgbarn

module-patterns

by lgbarn

Terraform/OpenTofu infrastructure development for AWS with EKS/Kubernetes support. Provides specialized agents for IaC development, security analysis, cost estimation, and state management.

0🍴 0📅 2025年12月23日
GitHubで見るManusで実行

SKILL.md


name: module-patterns description: Terraform module development patterns and best practices. Provides structure, versioning, and output scaffolds. Use when creating reusable modules.

Module Patterns

Terraform module development patterns and conventions.

Module Structure

Standard Layout

modules/
└── <module-name>/
    ├── main.tf           # Primary resources
    ├── variables.tf      # Input variables
    ├── outputs.tf        # Module outputs
    ├── versions.tf       # Version constraints
    ├── locals.tf         # Local values
    ├── data.tf           # Data sources (optional)
    ├── README.md         # Documentation
    ├── examples/
    │   ├── basic/
    │   │   ├── main.tf
    │   │   ├── outputs.tf
    │   │   └── README.md
    │   └── complete/
    │       ├── main.tf
    │       ├── outputs.tf
    │       └── README.md
    └── tests/
        ├── basic.tftest.hcl
        └── complete.tftest.hcl

versions.tf Pattern

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0"
    }
  }
}

variables.tf Patterns

Required Variable

variable "project" {
  description = "Project name used in resource naming"
  type        = string

  validation {
    condition     = can(regex("^[a-z][a-z0-9-]*$", var.project))
    error_message = "Project name must start with a letter and contain only lowercase letters, numbers, and hyphens."
  }
}

variable "environment" {
  description = "Environment name (dev, staging, prod)"
  type        = string

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

Optional with Default

variable "instance_type" {
  description = "EC2 instance type for compute resources"
  type        = string
  default     = "t3.medium"
}

variable "enable_encryption" {
  description = "Enable encryption at rest for all supported resources"
  type        = bool
  default     = true
}

Complex Type with Defaults

variable "node_groups" {
  description = "Map of EKS managed node group definitions"
  type = map(object({
    instance_types = list(string)
    min_size       = number
    max_size       = number
    desired_size   = number
    disk_size      = optional(number, 100)
    disk_type      = optional(string, "gp3")
    capacity_type  = optional(string, "ON_DEMAND")
    labels         = optional(map(string), {})
    taints = optional(list(object({
      key    = string
      value  = string
      effect = string
    })), [])
  }))
  default = {}
}

Sensitive Variable

variable "database_password" {
  description = "Database master password"
  type        = string
  sensitive   = true

  validation {
    condition     = length(var.database_password) >= 16
    error_message = "Database password must be at least 16 characters."
  }
}

Tags Variable

variable "tags" {
  description = "Additional tags to apply to all resources"
  type        = map(string)
  default     = {}
}

outputs.tf Patterns

Resource Identifiers

output "id" {
  description = "The ID of the primary resource"
  value       = aws_resource.this.id
}

output "arn" {
  description = "The ARN of the primary resource"
  value       = aws_resource.this.arn
}

Connection Information

output "endpoint" {
  description = "Endpoint for connecting to the resource"
  value       = aws_resource.this.endpoint
}

output "security_group_id" {
  description = "ID of the associated security group"
  value       = aws_security_group.this.id
}

Sensitive Outputs

output "connection_string" {
  description = "Database connection string"
  value       = "postgres://${var.username}:${random_password.db.result}@${aws_db_instance.this.endpoint}/${var.database_name}"
  sensitive   = true
}

Conditional Outputs

output "cluster_endpoint" {
  description = "EKS cluster endpoint (null if cluster not created)"
  value       = var.create_cluster ? module.eks[0].cluster_endpoint : null
}

output "private_subnets" {
  description = "List of private subnet IDs"
  value       = var.create_vpc ? module.vpc[0].private_subnets : var.private_subnet_ids
}

locals.tf Patterns

Name Construction

locals {
  name_prefix = "${var.project}-${var.environment}"

  resource_names = {
    cluster = "${local.name_prefix}-eks"
    vpc     = "${local.name_prefix}-vpc"
    rds     = "${local.name_prefix}-db"
  }
}

Tag Merging

locals {
  default_tags = {
    Project     = var.project
    Environment = var.environment
    Terraform   = "true"
    Module      = "module-name"
  }

  tags = merge(local.default_tags, var.tags)
}

Configuration Defaults

locals {
  node_group_defaults = {
    instance_types = ["m6i.large", "m5.large"]
    disk_size      = 100
    disk_type      = "gp3"
    capacity_type  = "ON_DEMAND"
  }

  node_groups = {
    for k, v in var.node_groups : k => merge(local.node_group_defaults, v)
  }
}

Conditional Logic

locals {
  create_kms_key = var.kms_key_arn == null
  kms_key_arn    = local.create_kms_key ? aws_kms_key.this[0].arn : var.kms_key_arn

  azs = var.azs != null ? var.azs : slice(data.aws_availability_zones.available.names, 0, 3)
}

main.tf Patterns

Conditional Resource Creation

resource "aws_kms_key" "this" {
  count = var.create_kms_key ? 1 : 0

  description             = "KMS key for ${local.name_prefix}"
  deletion_window_in_days = 7
  enable_key_rotation     = true

  tags = local.tags
}

For Each with Maps

resource "aws_subnet" "private" {
  for_each = var.private_subnets

  vpc_id            = aws_vpc.this.id
  availability_zone = each.value.az
  cidr_block        = each.value.cidr

  tags = merge(local.tags, {
    Name = "${local.name_prefix}-private-${each.key}"
    Type = "private"
  })
}

Lifecycle Rules

resource "aws_rds_cluster" "this" {
  cluster_identifier = local.resource_names.rds

  # ... configuration ...

  lifecycle {
    prevent_destroy = true
    ignore_changes  = [master_password]
  }
}

Timeouts

resource "aws_eks_cluster" "this" {
  name = local.resource_names.cluster

  # ... configuration ...

  timeouts {
    create = "45m"
    update = "60m"
    delete = "30m"
  }
}

Terraform Test Pattern

# tests/basic.tftest.hcl

provider "aws" {
  region = "us-east-1"
}

variables {
  project     = "test"
  environment = "dev"
}

run "validate_resources" {
  command = plan

  assert {
    condition     = aws_s3_bucket.this.bucket != null
    error_message = "S3 bucket should be created"
  }

  assert {
    condition     = aws_s3_bucket.this.tags["Environment"] == "dev"
    error_message = "Environment tag should be 'dev'"
  }
}

run "validate_naming" {
  command = plan

  assert {
    condition     = can(regex("^test-dev-", aws_s3_bucket.this.bucket))
    error_message = "Bucket name should follow naming convention"
  }
}

run "validate_encryption" {
  command = plan

  variables {
    enable_encryption = true
  }

  assert {
    condition     = length(aws_s3_bucket_server_side_encryption_configuration.this) > 0
    error_message = "Encryption should be enabled"
  }
}

README.md Template

# Module Name

Brief description of what this module creates.

## Usage

```hcl
module "example" {
  source = "path/to/module"

  project     = "myapp"
  environment = "prod"

  # Additional configuration
}

Requirements

NameVersion
terraform>= 1.5.0
aws>= 5.0

Providers

NameVersion
aws>= 5.0

Resources

NameType
aws_resource.nameresource
aws_data.namedata source

Inputs

NameDescriptionTypeDefaultRequired
projectProject namestringn/ayes
environmentEnvironmentstringn/ayes
tagsAdditional tagsmap(string){}no

Outputs

NameDescription
idResource ID
arnResource ARN

Examples

  • Basic - Minimal configuration
  • Complete - Full-featured configuration

License

Apache 2.0 Licensed.


## Example basic/main.tf

```hcl
provider "aws" {
  region = "us-east-1"
}

module "example" {
  source = "../../"

  project     = "myapp"
  environment = "dev"
}

output "id" {
  value = module.example.id
}

Moved Blocks for Refactoring

# moves.tf - Use when renaming resources
moved {
  from = aws_instance.web
  to   = aws_instance.application
}

moved {
  from = aws_s3_bucket.data
  to   = module.storage.aws_s3_bucket.main
}

moved {
  from = module.old_name
  to   = module.new_name
}

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新

+5
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

0/5
タグ

1つ以上のタグが設定されている

+5

レビュー

💬

レビュー機能は近日公開予定です