Terraform
Use when writing Terraform — AWS modules, resources, variables, outputs, remote state — even when the user just says 'provision this infra' or 'add an S3 bucket' without naming Terraform.From its SKILL.md
npx -y skills add event4u-app/agent-config --skill terraformAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 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
6.0 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it
terraform
When to use
Use this skill when writing or modifying Terraform configurations (.tf files), creating new infrastructure modules, or understanding AWS resource definitions.
Procedure: Write Terraform config
- Read the infrastructure repo structure (check
agents/overrides/skills/terraform.mdfor the repo location). - Check existing modules in
modules/for patterns and conventions. - Read
variables.tfof the target module to understand required inputs. - Check
versions.tffor provider version constraints.
Project structure (typical)
{infrastructure-repo}/
├── environments/
│ ├── pro/ # Production environment
│ │ ├── root.hcl # Terragrunt root config
│ │ ├── core/ # Core infrastructure (VPC, DNS zones)
│ │ └── {service}/ # Per-service resources
│ └── sta/ # Stage environment
│ └── ...
├── modules/
│ ├── core/ # VPC, DNS, shared resources
│ └── {service}/ # Per-service module (ECS, ALB, ECR, etc.)
└── Taskfile.yml # Task runner commands (or Makefile)
Read agents/overrides/skills/terraform.md for the actual repository layout and service names.
Conventions
Provider versions
- Always pin provider versions in
versions.tf. - Check
versions.tfin the existing modules for the project's version constraints.
Module sources
Prefer community or organization-specific Terraform modules from the Terraform Registry:
module "alb" {
source = "{org}/application-load-balancer/aws"
version = ">= 1.0.0, < 2.0.0"
}
Check existing modules in the project for which registry modules are used.
Naming
- Resource prefix:
var.global_prefix(e.g.,{project}-{env}) - All resources must include
tags = var.tags - Security groups:
${var.global_prefix}-<purpose>(e.g.,-ecs,-mysql,-redis) - Log groups:
/aws/ecs/${cluster}/${service}
State management
- Remote state in S3 with DynamoDB locking.
- State is encrypted.
- Key pattern:
${path_relative_to_include()}/terraform.tfstate
Variables
- Use typed
variableblocks withdescription. - Use
object()types for complex inputs (notanyunless unavoidable). - Use
optional()with defaults where appropriate. - Group variables by domain (naming, network, ECS, Redis, database, etc.).
Lifecycle rules
- Use
ignore_changes = [task_definition]on ECS services — task definitions are managed by CI/CD, not Terraform. - Use
deletion_protection = trueon databases.
Security
- OIDC authentication for GitHub Actions (no long-lived credentials).
- Secrets stored in AWS Secrets Manager.
- Security groups follow least-privilege: only allow traffic between known services.
- IAM policies use specific resource ARNs, not wildcards (except where unavoidable).
Common patterns
ECS service with CodeDeploy (Blue/Green)
Used for web services with zero-downtime deployments:
- ALB → Target Group → ECS Service
- CodeDeploy handles traffic shifting
- Auto-rollback on CloudWatch alarms (5xx error rate)
ECS service without CodeDeploy
Used for workers and schedulers:
- Direct ECS service update
deployment_controller { type = "ECS" }lifecycle { ignore_changes = [task_definition] }
GitHub OIDC IAM role
Each environment has a GitHub IAM role with:
- OIDC trust policy (scoped to repo + environment)
- Policies for ECR push/pull, ECS deployment, Secrets Manager read, CloudWatch logs
Output format
- Terraform configuration files (.tf) with proper module structure
- Variables, outputs, and state management config
Auto-trigger keywords
- Terraform
- AWS infrastructure
- modules
- resources
- state management
Known pitfalls
| Symptom | Root cause | Fix |
|---|---|---|
Error acquiring the state lock blocks every command | A prior apply crashed / was killed and left the lock held (DynamoDB / backend lock) | Confirm no apply is actually running, then terraform force-unlock <lock-id> — never delete the lock table |
plan wants to destroy+recreate a resource after a rename | Renaming a resource block changes its address; Terraform sees the old address gone and a new one added | terraform state mv <old.addr> <new.addr> (or a moved {} block) so it tracks the same object |
count/for_each errors with "value depends on resource attributes that cannot be determined until apply" | The count/for_each expression reads an unknown (not-yet-created) value | Key for_each off a static/known map, or split into a two-stage apply with -target |
A change applies but the next plan shows the same diff again (perpetual diff) | The provider normalizes/computes the attribute differently than written (ordering, defaults, case) | Match the provider's canonical form, or ignore_changes on that attribute in lifecycle |
plan shows a resource as tainted/replaced after a manual console change | Out-of-band drift — someone edited the resource outside Terraform | terraform apply -refresh-only to reconcile state, then decide code-vs-cloud; stop the manual edits |
Gotcha
terraform applywithout-auto-approverequires interactive confirmation — don't use in CI without the flag.- The model forgets to run
terraform planbeforeapply— always plan first, review changes. - State files contain sensitive data — never commit them to Git. Use remote state (S3 + DynamoDB).
Do NOT
- Do NOT use
*in IAM resource ARNs unless absolutely necessary. - Do NOT remove
deletion_protectionfrom databases. - Do NOT change provider versions without testing in Stage first.
- Do NOT hardcode AWS account IDs — use
data.aws_caller_identity.current.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.