agentsclimarketplace

Terraform opentofu module architecture

Skill hamzabellouch/agent-skills/Infrastructure as Code and Edge/terraform-opentofu-module-architecture

Master production-grade Terraform and OpenTofu module architecture, state management, dependency injection, testing, and multi-environment orchestration.From its SKILL.md

Install
npx -y skills add hamzabellouch/agent-skills --skill terraform-opentofu-module-architecture

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 22 days oldThe repository was created 22 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

8.5 KB, ~2.0k tokens by cl100k_base, as published. Nobody here has run it

Terraform & OpenTofu Module Architecture Skill Guide

This skill provides comprehensive standards, production patterns, anti-patterns, and actionable code guidelines for designing, building, testing, and maintaining modular Infrastructure as Code (IaC) using Terraform and OpenTofu.


1. Core Principles & Architecture Guidelines

  1. Strict Separation of Concerns:

    • Root Modules (Live/Environments): Instantiate reusable modules with environment-specific input values. Never contain resource declarations directly when reusable modules can be authored.
    • Child Modules (Reusable Component): Abstract infrastructure resources into logical units (e.g., VPC, EKS/GKE, RDS/Cloud SQL). Must be environment-agnostic, parameter-driven, and highly composable.
  2. Standard Module Directory Structure:

    terraform-provider-name-modulename/
    ├── main.tf              # Primary resource definitions & orchestrations
    ├── variables.tf         # Typed input variables with defaults & validation rules
    ├── outputs.tf           # Explicit outputs with meaningful descriptions & types
    ├── versions.tf          # Required terraform/opentofu version & provider constraints
    ├── dependencies.tf      # Remote state data sources, provider bindings, or internal locals
    ├── README.md            # Auto-generated documentation (terraform-docs)
    ├── examples/            # Runnable implementations
    │   ├── complete/        # Fully featured environment setup
    │   └── minimal/         # Basic getting-started configuration
    └── tests/               # Automated unit/integration tests (Native / Terratest)
        ├── unit_test.tftest.hcl
        └── integration_test.tftest.hcl
    
  3. Immutability & State Management:

    • Remote backend with explicit state locking (DynamoDB / S3, GCS, Cloudflare R2, or OpenTofu S3/HTTP backends).
    • Never share state files across separate environments or environments with different lifecycles; isolate by directory or repository (prefer directory-based layout over workspace-based layout for separate clouds/environments).

2. Production Code Standards & Examples

A. Defensive Variable Definition & Validations (variables.tf)

Always define explicit types, descriptions, and custom validation blocks.

variable "environment" {
  type        = string
  description = "Deployment environment name (e.g., dev, staging, prod)."

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Allowed values for environment are 'dev', 'staging', or 'prod'."
  }
}

variable "vpc_cidr" {
  type        = string
  description = "IPv4 CIDR block for the VPC network."
  default     = "10.0.0.0/16"

  validation {
    condition     = can(cidrnetmask(var.vpc_cidr))
    error_message = "Must be a valid IPv4 CIDR notation (e.g., 10.0.0.0/16)."
  }
}

variable "subnet_configuration" {
  type = map(object({
    cidr_block        = string
    availability_zone = string
    public            = bool
    tags              = optional(map(string), {})
  }))
  description = "Map of subnets to create within the network module."

  validation {
    condition = alltrue([
      for sub in values(var.subnet_configuration) : can(cidrnetmask(sub.cidr_block))
    ])
    error_message = "All subnets must specify a valid IPv4 CIDR block."
  }
}

B. Clean Resource Declarations & Local Conventions (main.tf)

Use locals to compute tag sets, naming conventions, and conditional configurations centrally.

locals {
  name_prefix = "${var.project_name}-${var.environment}"
  
  default_tags = merge(
    var.tags,
    {
      Environment = var.environment
      ManagedBy   = "Terraform/OpenTofu"
      Project     = var.project_name
    }
  )
}

resource "aws_s3_bucket" "this" {
  bucket        = "${local.name_prefix}-data-store"
  force_destroy = var.environment == "dev" ? true : false

  tags = local.default_tags
}

resource "aws_s3_bucket_versioning" "this" {
  bucket = aws_s3_bucket.this.id

  versioning_configuration {
    status = var.enable_versioning ? "Enabled" : "Suspended"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
  bucket = aws_s3_bucket.this.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = var.kms_key_arn
      sse_algorithm     = var.kms_key_arn != null ? "aws:kms" : "AES256"
    }
  }
}

C. Explicit Outputs (outputs.tf)

Always return full object references or specific attributes with explicit descriptions. Never leak unencrypted secrets unless explicitly intended (mark sensitive = true).

output "bucket_id" {
  value       = aws_s3_bucket.this.id
  description = "The name/ID of the created S3 bucket."
}

output "bucket_arn" {
  value       = aws_s3_bucket.this.arn
  description = "The Amazon Resource Name (ARN) of the S3 bucket."
}

output "database_connection_string" {
  value       = "postgres://${aws_db_instance.this.username}:${aws_db_instance.this.password}@${aws_db_instance.this.endpoint}/${aws_db_instance.this.db_name}"
  description = "Full PostgreSQL connection string."
  sensitive   = true
}

3. Native OpenTofu & Terraform Testing Framework (tests/)

Use native .tftest.hcl test suites to validate logic without third-party dependencies.

# tests/unit_test.tftest.hcl
run "verify_bucket_naming_and_tags" {
  command = plan

  variables {
    project_name      = "myproject"
    environment       = "dev"
    enable_versioning = true
    tags              = { CostCenter = "12345" }
  }

  assert {
    condition     = aws_s3_bucket.this.bucket == "myproject-dev-data-store"
    error_message = "S3 bucket name generated does not match expected convention."
  }

  assert {
    condition     = aws_s3_bucket.this.tags["ManagedBy"] == "Terraform/OpenTofu"
    error_message = "ManagedBy tag was not injected correctly."
  }
}

run "verify_production_encryption" {
  command = plan

  variables {
    project_name      = "myproject"
    environment       = "prod"
    kms_key_arn       = "arn:aws:kms:us-east-1:123456789012:key/abc-123"
    enable_versioning = true
  }

  assert {
    condition     = aws_s3_bucket_server_side_encryption_configuration.this.rule[0].apply_server_side_encryption_by_default[0].sse_algorithm == "aws:kms"
    error_message = "KMS encryption must be applied when kms_key_arn is provided."
  }
}

4. Anti-Patterns & Pitfalls

Anti-PatternWhy it FailsProduction Solution
Hardcoding Provider Blocks in Child ModulesPrevents module users from configuring custom regions, multi-region aliases, or authentication credentials.Define required_providers in child modules; let root module pass providers via providers = { aws = aws.eu_west_1 }.
Monolithic State FilesIncreases blast radius of terraform destroy or state corruptions; slows terraform plan execution down.Break infrastructure into isolated layers (e.g., 0-network/, 1-database/, 2-apps/).
Overusing count for Complex MapsModifying items in an array indexed by count causes full re-creation of subsequent resources.Use for_each with maps or set expressions.
Unset or Weak Variable ConstraintsFails late during apply phase rather than early during validation/plan.Use custom validation blocks and explicit types (object, map, list).
Dynamic Provisioners (local-exec / remote-exec)Impairs drift detection, idempotency, and portability across OS execution hosts.Use cloud-native user-data scripts, cloud-init, Ansible, or Kubernetes controllers instead.

5. Automated CI/CD & Drift Detection Workflow

graph TD
    A[Git Push / PR] --> B[terraform fmt -check]
    B --> C[tflint / opentofu fmt]
    C --> D[trivy / tfsec Security Scan]
    D --> E[tftest / Terratest Validation]
    E --> F[terraform plan / tofu plan]
    F --> G{PR Merged?}
    G -- Yes --> H[terraform apply / tofu apply]
    G -- No --> I[End PR Feedback Loop]

Essential CLI Operations Matrix

  • Validate Code Formatting: tofu fmt -recursive -check
  • Lint Code: tflint --recursive
  • Run Native Tests: tofu test
  • Plan targeted changes: tofu plan -out=tfplan -target=module.vpc
  • State Operations: tofu state mv <source> <destination> / tofu state rm <resource>

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,861. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.