{"id":"2bb02d47-69cc-4cad-8667-da948e083de5","shortId":"NNHqKj","kind":"skill","title":"terraform","tagline":">-","description":"# Terraform & OpenTofu\n\n## File Organization & Naming\n\n| File | Purpose |\n|------|---------|\n| `terraform.tf` | Terraform + provider version requirements |\n| `providers.tf` | Provider configurations |\n| `main.tf` | Primary resources and data sources |\n| `variables.tf` | Input variables (alphabetical) |\n| `outputs.tf` | Output values (alphabetical) |\n| `locals.tf` | Local values |\n\n- Lowercase with underscores: `web_api`, not `webAPI` or `web-api`\n- Descriptive nouns excluding resource type: `aws_instance.web_api` not `aws_instance.web_api_instance`\n- Singular, not plural\n- `this` for singleton resources (one of that type per module)\n- Contextual variable prefixes: `vpc_cidr_block` not `cidr`\n\n## Block Ordering\n\n**Resources:** `count`/`for_each` (blank line after) → arguments → nested blocks → `tags` → `depends_on` → `lifecycle` (last)\n\n**Variables:** `description` → `type` → `default` → `validation` → `nullable`\n\nEvery variable needs `type` + `description`. Every output needs `description`. Mark secrets `sensitive = true`.\n\n## Module Structure\n\n| Type | Scope | Example |\n|------|-------|---------|\n| Resource Module | Single logical group | VPC + subnets, SG + rules |\n| Infrastructure Module | Collection of resource modules | Networking + compute for one region |\n| Composition | Complete infrastructure | Spans regions/accounts |\n\n```\nmodule-name/\n├── main.tf, variables.tf, outputs.tf, versions.tf\n├── examples/\n│   ├── minimal/\n│   └── complete/\n└── tests/\n    └── defaults.tftest.hcl\n```\n\nKeep modules small (single responsibility). `examples/` double as documentation and integration test fixtures. Semantic versioning for all published modules.\n\n## count vs for_each\n\n| Scenario | Use |\n|----------|-----|\n| Boolean toggle (create or skip) | `count = condition ? 1 : 0` |\n| Named/keyed items that may reorder | `for_each = toset(list)` or `map` |\n| Fixed identical replicas | `count = N` |\n\nDefault to `for_each` -- removing a middle item from a `count` list recreates all subsequent resources. Use `count` only for boolean conditionals or truly identical replicas.\n\n## Testing\n\n| Situation | Approach |\n|-----------|----------|\n| Quick validation | `terraform fmt -check && terraform validate` |\n| Pre-commit | + `tflint` + `trivy config .` / `checkov -d .` |\n| Logic validation (1.6+) | Native `terraform test` with `command = plan` |\n| Cost-free unit tests (1.7+) | Native tests + `mock_provider` |\n| Real infra validation | Native tests with `command = apply`, or Terratest (Go) |\n\n**Native test essentials** (`.tftest.hcl` in `tests/`):\n- `command = plan` for fast unit tests; `command = apply` for integration (default)\n- `assert { condition = expr; error_message = \"...\" }` -- multiple per run block\n- `expect_failures = [var.name]` for negative testing (validate rejection of bad input)\n- `mock_provider \"aws\" { mock_resource \"...\" { defaults = { ... } } }` -- plan-mode only, no credentials, fast CI\n- `variables {}` at file level (all runs) or within a `run` block (override)\n- Reference prior run outputs: `run.setup.vpc_id`\n- `parallel = true` on independent runs with separate state -- creates sync point at next sequential run\n- `state_key = \"name\"` required for `parallel = true` runs with independent state\n- File naming: `*_unit_test.tftest.hcl` (plan mode) vs `*_integration_test.tftest.hcl` (apply mode)\n\n## Version Pinning\n\n| Component | Strategy | Example |\n|-----------|----------|---------|\n| Terraform | Pin minor | `required_version = \"~> 1.9\"` |\n| Providers | Pin major | `version = \"~> 5.0\"` |\n| Modules (prod) | Pin exact | `version = \"5.1.2\"` |\n| Modules (dev) | Allow patch | `version = \"~> 5.1\"` |\n\nKey modern features: `moved` blocks (1.1+), `optional()` with defaults (1.3+), native testing (1.6+), mock providers (1.7+), cross-variable validation (1.9+), write-only arguments (1.11+).\nStacks (HCP, preview): orchestrates multiple configs as a single deployment unit -- evaluate for multi-environment patterns.\n\n## State & Security\n\n- Remote backend with locking: S3+DynamoDB, Azure Blob, GCS, or Terraform Cloud. Never local state for shared infrastructure.\n- Encrypt state at rest. Never commit `.tfstate`, `.terraform/`, or `*.tfplan`. Always commit `.terraform.lock.hcl`.\n- `default_tags` on provider for consistent resource tagging.\n- Encryption at rest on all storage. Private networking by default -- public access is opt-in.\n- Least-privilege security groups. No `0.0.0.0/0` ingress without explicit justification.\n- Never hardcode credentials -- use assume_role, OIDC, or secrets managers.\n- Pre-commit: `terraform fmt -recursive && terraform validate && trivy config .`\n- `moved { from = old; to = new }` for refactoring resource names/modules without destroy-recreate. Remove block after apply.\n\n## Troubleshooting\n\n- State lock stuck: `terraform force-unlock <ID>` -- only after confirming no other operation running\n- Resource drift: `terraform plan -refresh-only` to detect, `terraform apply -refresh-only` to accept\n- Replace tainted: `terraform apply -replace=ADDR` (not deprecated `terraform taint`)\n- Import existing: `import` blocks (1.5+) for declarative import, or `terraform import ADDR ID`\n\n## Dependency Management\n\nUse `locals` with `try()` to control deletion ordering without explicit `depends_on`:\n\n```hcl\nlocals {\n  vpc_id = try(aws_vpc_ipv4_cidr_block_association.this[0].vpc_id, aws_vpc.this.id, \"\")\n}\n```\n\nThis forces Terraform to destroy subnets before CIDR associations -- prevents deletion errors.\n\n- `cidrsubnet(var.vpc_cidr, 8, count.index)` for calculated subnet CIDRs -- never hardcode subnets\n- Multi-region: `provider \"aws\" { alias = \"eu_west_1\" }` + `providers = { aws = aws.eu_west_1 }` in module blocks\n\n## Verify\n\nRun before declaring done:\n\n```bash\nterraform fmt -check && terraform validate && tflint && trivy config .\n```\n\nAll commands must pass with zero errors.","tags":["terraform","skills","iliaal","agent-skills","ai-coding-assistant","ai-tools","claude-code"],"capabilities":["skill","source-iliaal","skill-terraform","topic-agent-skills","topic-ai-coding-assistant","topic-ai-tools","topic-claude-code","topic-skills"],"categories":["ai-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/iliaal/ai-skills/terraform","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add iliaal/ai-skills","source_repo":"https://github.com/iliaal/ai-skills","install_from":"skills.sh"}},"qualityScore":"0.456","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 13 github stars · SKILL.md body (5,869 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:04.083Z","embedding":null,"createdAt":"2026-05-09T01:05:37.167Z","updatedAt":"2026-05-18T19:07:04.083Z","lastSeenAt":"2026-05-18T19:07:04.083Z","tsv":"'/0':518 '0':188,634 '0.0.0.0':517 '1':187,670,675 '1.1':416 '1.11':436 '1.3':420 '1.5':605 '1.6':251,423 '1.7':263,426 '1.9':393,431 '5.0':398 '5.1':410 '5.1.2':404 '8':653 'accept':590 'access':506 'addr':596,612 'alia':667 'allow':407 'alphabet':26,30 'alway':484 'api':38,44,51,54 'appli':275,292,381,559,585,594 'approach':233 'argument':86,435 'assert':296 'associ':646 'assum':527 'aw':318,666,672 'aws.eu':673 'aws_instance.web':50,53 'aws_vpc.this.id':637 'aws_vpc_ipv4_cidr_block_association.this':633 'azur':462 'backend':457 'bad':314 'bash':684 'blank':83 'blob':463 'block':74,77,88,304,340,415,557,604,678 'boolean':180,225 'calcul':656 'check':238,687 'checkov':247 'ci':329 'cidr':73,76,645,652,658 'cidrsubnet':650 'cloud':467 'collect':129 'command':256,274,285,291,694 'commit':243,479,485,535 'complet':139,152 'compon':385 'composit':138 'comput':134 'condit':186,226,297 'config':246,442,542,692 'configur':16 'confirm':570 'consist':492 'contextu':69 'control':621 'cost':259 'cost-fre':258 'count':80,174,185,203,215,222 'count.index':654 'creat':182,356 'credenti':327,525 'cross':428 'cross-vari':427 'd':248 'data':21 'declar':607,682 'default':97,205,295,321,419,487,504 'defaults.tftest.hcl':154 'delet':622,648 'depend':90,614,626 'deploy':446 'deprec':598 'descript':45,95,104,108 'destroy':554,642 'destroy-recr':553 'detect':583 'dev':406 'document':163 'done':683 'doubl':161 'drift':576 'dynamodb':461 'encrypt':474,495 'environ':452 'error':299,649,699 'essenti':281 'eu':668 'evalu':448 'everi':100,105 'exact':402 'exampl':117,150,160,387 'exclud':47 'exist':602 'expect':305 'explicit':521,625 'expr':298 'failur':306 'fast':288,328 'featur':413 'file':4,7,332,374 'fix':200 'fixtur':167 'fmt':237,537,686 'forc':566,639 'force-unlock':565 'free':260 'gcs':464 'go':278 'group':122,515 'hardcod':524,660 'hcl':628 'hcp':438 'id':347,613,631,636 'ident':201,229 'import':601,603,608,611 'independ':351,372 'infra':269 'infrastructur':127,140,473 'ingress':519 'input':24,315 'instanc':55 'integr':165,294 'integration_test.tftest.hcl':380 'item':190,212 'justif':522 'keep':155 'key':364,411 'last':93 'least':512 'least-privileg':511 'level':333 'lifecycl':92 'line':84 'list':197,216 'local':32,469,617,629 'locals.tf':31 'lock':459,562 'logic':121,249 'lowercas':34 'main.tf':17,146 'major':396 'manag':532,615 'map':199 'mark':109 'may':192 'messag':300 'middl':211 'minim':151 'minor':390 'mock':266,316,319,424 'mode':324,378,382 'modern':412 'modul':68,113,119,128,132,144,156,173,399,405,677 'module-nam':143 'move':414,543 'multi':451,663 'multi-environ':450 'multi-region':662 'multipl':301,441 'must':695 'n':204 'name':6,145,365,375 'named/keyed':189 'names/modules':551 'nativ':252,264,271,279,421 'need':102,107 'negat':309 'nest':87 'network':133,502 'never':468,478,523,659 'new':547 'next':360 'noun':46 'nullabl':99 'oidc':529 'old':545 'one':63,136 'opentofu':3 'oper':573 'opt':509 'opt-in':508 'option':417 'orchestr':440 'order':78,623 'organ':5 'output':28,106,345 'outputs.tf':27,148 'overrid':341 'parallel':348,368 'pass':696 'patch':408 'pattern':453 'per':67,302 'pin':384,389,395,401 'plan':257,286,323,377,578 'plan-mod':322 'plural':58 'point':358 'pre':242,534 'pre-commit':241,533 'prefix':71 'prevent':647 'preview':439 'primari':18 'prior':343 'privat':501 'privileg':513 'prod':400 'provid':11,15,267,317,394,425,490,665,671 'providers.tf':14 'public':505 'publish':172 'purpos':8 'quick':234 'real':268 'recreat':217,555 'recurs':538 'refactor':549 'refer':342 'refresh':580,587 'refresh-on':579,586 'region':137,664 'regions/accounts':142 'reject':312 'remot':456 'remov':209,556 'reorder':193 'replac':591,595 'replica':202,230 'requir':13,366,391 'resourc':19,48,62,79,118,131,220,320,493,550,575 'respons':159 'rest':477,497 'role':528 'rule':126 'run':303,335,339,344,352,362,370,574,680 'run.setup.vpc':346 's3':460 'scenario':178 'scope':116 'secret':110,531 'secur':455,514 'semant':168 'sensit':111 'separ':354 'sequenti':361 'sg':125 'share':472 'singl':120,158,445 'singleton':61 'singular':56 'situat':232 'skill' 'skill-terraform' 'skip':184 'small':157 'sourc':22 'source-iliaal' 'span':141 'stack':437 'state':355,363,373,454,470,475,561 'storag':500 'strategi':386 'structur':114 'stuck':563 'subnet':124,643,657,661 'subsequ':219 'sync':357 'tag':89,488,494 'taint':592,600 'terraform':1,2,10,236,239,253,388,466,481,536,539,564,577,584,593,599,610,640,685,688 'terraform.lock.hcl':486 'terraform.tf':9 'terratest':277 'test':153,166,231,254,262,265,272,280,284,290,310,422 'tflint':244,690 'tfplan':483 'tfstate':480 'tftest.hcl':282 'toggl':181 'topic-agent-skills' 'topic-ai-coding-assistant' 'topic-ai-tools' 'topic-claude-code' 'topic-skills' 'toset':196 'tri':619,632 'trivi':245,541,691 'troubleshoot':560 'true':112,349,369 'truli':228 'type':49,66,96,103,115 'underscor':36 'unit':261,289,447 'unit_test.tftest.hcl':376 'unlock':567 'use':179,221,526,616 'valid':98,235,240,250,270,311,430,540,689 'valu':29,33 'var.name':307 'var.vpc':651 'variabl':25,70,94,101,330,429 'variables.tf':23,147 'verifi':679 'version':12,169,383,392,397,403,409 'versions.tf':149 'vpc':72,123,630,635 'vs':175,379 'web':37,43 'web-api':42 'webapi':40 'west':669,674 'within':337 'without':520,552,624 'write':433 'write-on':432 'zero':698","prices":[{"id":"9fec0754-5880-4e27-82e4-11cf4fad94bc","listingId":"2bb02d47-69cc-4cad-8667-da948e083de5","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"iliaal","category":"ai-skills","install_from":"skills.sh"},"createdAt":"2026-05-09T01:05:37.167Z"}],"sources":[{"listingId":"2bb02d47-69cc-4cad-8667-da948e083de5","source":"github","sourceId":"iliaal/ai-skills/terraform","sourceUrl":"https://github.com/iliaal/ai-skills/tree/master/skills/terraform","isPrimary":false,"firstSeenAt":"2026-05-09T01:05:37.167Z","lastSeenAt":"2026-05-18T19:07:04.083Z"}],"details":{"listingId":"2bb02d47-69cc-4cad-8667-da948e083de5","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"iliaal","slug":"terraform","github":{"repo":"iliaal/ai-skills","stars":13,"topics":["agent-skills","ai-coding-assistant","ai-tools","claude-code","skills"],"license":"mit","html_url":"https://github.com/iliaal/ai-skills","pushed_at":"2026-05-16T13:15:17Z","description":"Curated collection of agent skills for AI coding assistants.","skill_md_sha":"b179d12c06d49e8e69e8a549a549ab7cfb4f5014","skill_md_path":"skills/terraform/SKILL.md","default_branch":"master","skill_tree_url":"https://github.com/iliaal/ai-skills/tree/master/skills/terraform"},"layout":"multi","source":"github","category":"ai-skills","frontmatter":{"name":"terraform","description":">-"},"skills_sh_url":"https://skills.sh/iliaal/ai-skills/terraform"},"updatedAt":"2026-05-18T19:07:04.083Z"}}