skills/terraform-module-builder/SKILL.md
Reusable Terraform module builder for AWS, GCP, and Azure infrastructure. Activate on: Terraform module, reusable IaC, provider configuration, state management, module registry, workspace management. NOT for: Kubernetes manifests (use kubernetes-manifest-generator), AWS CDK (use aws-cdk-builder), application deployment (use devops-automator).
npx skillsauth add curiositech/windags-skills terraform-module-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert in building composable, tested, and version-controlled Terraform modules for multi-cloud infrastructure.
Module Size Decision Tree:
├─ Resource count > 50 OR complexity score > 8?
│ ├─ YES → Split into sub-modules with clear interfaces
│ └─ NO → Continue as single module
├─ Multiple provider types (AWS + GCP + K8s)?
│ ├─ YES → Separate modules per provider
│ └─ NO → Single provider module acceptable
└─ Team size > 15 OR multiple product teams?
├─ YES → Create module registry with versioning
└─ NO → Git submodules or local modules sufficient
| Team Size | Maturity | Backend Choice | Lock Mechanism | |-----------|----------|---------------|----------------| | 1-3 devs | Startup | Terraform Cloud Free | Built-in | | 4-10 devs | Growth | S3 + DynamoDB | DynamoDB table | | 10+ devs | Enterprise | S3 + DynamoDB OR Terraform Cloud Team | DynamoDB + state encryption | | Regulated | Any size | Self-hosted Consul OR Terraform Enterprise | Consul locks + audit logs |
Conditional Resource Decision:
IF environment_specific AND known_at_plan_time
→ Use count = var.enable_feature ? 1 : 0
IF data_driven AND multiple_instances
→ Use for_each with map of configurations
IF complex_branching OR resource_relationships
→ Use dynamic blocks with local values
Symptom: terraform plan takes >30 seconds, module has >50 resources, single file >1000 lines
Diagnosis: Module violates single responsibility principle
Fix: Extract logical boundaries (networking, compute, data) into separate modules with defined interfaces
Symptom: Error: provider "aws" was not configured by any provider blocks in child modules
Diagnosis: Child module declares provider block instead of inheriting from parent
Fix: Remove provider blocks from child modules, add only required_providers in versions.tf
Symptom: Resources recreate when boolean conditions change order: aws_instance.web[0] → aws_instance.web[1]
Diagnosis: Using count with conditional lists instead of for_each with stable keys
Fix: Replace count = length(var.subnets) with for_each = toset(var.subnets)
Symptom: "Backend configuration changed" errors, state file conflicts between team members
Diagnosis: Mixing local and remote state, or inconsistent backend configuration
Fix: Standardize on remote backend with locking, use terraform init -reconfigure
Symptom: Plan succeeds but apply fails with provider errors like "invalid CIDR" or "region not found"
Diagnosis: Missing input validation allows invalid values to reach provider
Fix: Add validation blocks: condition = can(cidrhost(var.cidr, 0))
Scenario: E-commerce module needs optional read replica based on environment and expected load.
Decision Process:
var.environment = "prod", var.expected_read_iops = 5000Implementation Choice:
# Option 1: count (avoid - creates aws_db_instance.replica[0])
resource "aws_db_instance" "replica" {
count = var.environment == "prod" && var.expected_read_iops > 3000 ? 1 : 0
# Problem: Index-based addressing, brittle to condition changes
}
# Option 2: for_each (preferred - creates aws_db_instance.replica["primary"])
resource "aws_db_instance" "replica" {
for_each = var.enable_read_replica ? { primary = var.replica_config } : {}
# Benefit: Stable resource addressing, easier to extend to multiple replicas
}
Novice Miss: Using boolean count without considering future extensibility
Expert Catch: Planning for multiple replicas (by region, by workload) using map-based for_each
Cost Impact: Production with replica = $400/month vs $200/month single instance
Do NOT use for:
kubernetes-manifest-generator for YAML/Helmaws-cdk-builder for TypeScript/Python CDK stacksdevops-automator for CI/CD workflowsterraform-iac-expert for ad-hoc TerraformWhen to delegate:
kubernetes-manifest-generatoraws-cdk-builderdevops-automatortools
Building resilient distributed systems with circuit breakers, retries with full-jitter exponential backoff, retry budgets (per-request 3-attempt + per-client 10% ratio per Google SRE), deadline propagation, and the cascading-failure math (4 layers × 3 retries = 64x amplification). Grounded in Resilience4j, Microsoft Cloud Patterns, AWS Architecture Blog (Marc Brooker), and Google SRE Book.
testing
Designing HTTP cache headers that work correctly across browsers, CDNs, and shared proxies — `Cache-Control` directives per RFC 9111, `stale-while-revalidate` and `stale-if-error` per RFC 5861, the Vary header for varying responses, and surrogate keys for tag-based purging. Grounded in IETF RFCs and Cloudflare/Fastly docs.
development
Use when designing or fixing a Content Security Policy on a real site, choosing between nonce-based and hash-based CSP, adding strict-dynamic, debugging "Refused to execute inline script" errors, deploying CSP in report-only mode first, configuring report-to / report-uri, or auditing an existing policy for unsafe-inline / unsafe-eval / wildcards. Triggers: "CSP blocks legitimate inline script", strict-dynamic, nonce-{RANDOM}, sha256-{HASH}, object-src none, base-uri none, frame-ancestors, Trusted Types, X-Content-Security-Policy obsolete, report-only vs enforced. NOT for general HTTP security headers (HSTS, COOP/COEP), Trusted Types deep dive, CORS configuration, or building a WAF.
tools
Choosing and operating an HTTP API versioning strategy that doesn't break clients — Stripe's date-based pinned versions, the Deprecation/Sunset header pair (RFC 9745 + RFC 8594), URI vs header vs media-type approaches, and the version-transformer pattern. Grounded in Stripe's published architecture and IETF RFCs.