terraform-patterns
**UTILITY SKILL** — Reusable Azure Terraform patterns: hub-spoke, private endpoints, diagnostics, AVM-TF modules. WHEN: "hub-spoke Terraform", "private endpoint module", "AVM-TF composition", "diagnostic settings", "plan interpretation". DO NOT USE FOR: Bicep code (azure-bicep-patterns), ADRs (azure-adr), diagrams (drawio).
git clone --depth 1 https://github.com/jonathan-vella/apex /tmp/terraform-patterns && cp -r /tmp/terraform-patterns/.github/skills/terraform-patterns ~/.claude/skills/terraform-patternsSKILL.md
# Azure Terraform Patterns Skill
Composable architecture building blocks for Azure Terraform. Complements
`iac-terraform-best-practices.instructions.md` (style) and `azure-defaults` skill (naming, tags, regions).
> **Canonical sources** — the security baseline, AVM-first mandate, naming
> conventions, required tags, and unique-suffix rule live in
> [`azure-defaults/SKILL.md`](../azure-defaults/SKILL.md) and
> [`iac-policy-compliance.md`](../../instructions/references/iac-policy-compliance.md).
> This skill restates the rules tersely below for IaC-output convenience
> only; in conflict, the canonical sources win.
---
## Quick Reference
| Pattern | When to Use | Reference |
| ------------------------ | ------------------------------------------------ | ------------------------------------------ |
| Hub-Spoke Networking | Multi-workload environments with shared services | `references/hub-spoke-pattern.md` |
| Private Endpoint Wiring | Any PaaS service requiring private connectivity | `references/private-endpoint-pattern.md` |
| Diagnostic Settings | Every deployed resource (mandatory) | `references/common-patterns.md` |
| Conditional Deployment | Optional resources controlled by variables | `references/common-patterns.md` |
| Module Composition | Calling multiple AVM modules in root module | See inline example below |
| Managed Identity | Any service-to-service authentication | `references/common-patterns.md` |
| Budget & Cost Monitoring | Every deployment (mandatory) | `references/budget-pattern.md` |
| Plan Interpretation | Pre-deployment validation and change analysis | `references/plan-interpretation.md` |
| AVM Pitfalls | Set-type diffs, provider pins, 4.x changes | `references/avm-pitfalls.md` |
| AVM Authoring | AVM certification requirements, compliance | `references/avm-authoring-requirements.md` |
| Module Refactoring | Monolith → module extraction, state migration | `references/refactor-module.md` |
---
## Canonical Example — Module Composition
Wire AVM child modules by passing outputs as inputs (`module.<name>.<output>`); never
hardcode IDs. **AVM-TF module versions in APEX-generated code MUST be exact semver
(`version = "X.Y.Z"`)** — pinned at plan time from
`registry.terraform.io` (newest stable in `modules[0].versions[]`). Range
constraints (`~> X.Y`, `>= X.Y.Z`) are NOT allowed in `04-iac-contract.json` and
will be flagged by `npm run validate:avm-versions`. Full code sample
(resource group + key vault) and rationale in
[`references/module-composition.md`](references/module-composition.md).
---
## Rules
- **AVM-first**: Use `Azure/avm-res-*` registry modules over raw `azurerm_*` resources
- **AVM-TF version pins**: Exact semver only (`version = "X.Y.Z"`) — resolve the latest stable via `registry.terraform.io/v1/modules/Azure/avm-res-{path}/azurerm/versions` at plan time. Stale pins need a `pin_policy.mode = "exception"` block in `04-iac-contract.json`. Range constraints (`~>`, `>=`) are flagged by `validate:avm-versions`.
- **Hub-spoke**: Spokes peer to hub only; never spoke-to-spoke
- **Private endpoints**: Three resources per service — PE, DNS zone, VNet link
- **Diagnostics**: Every resource MUST have a diagnostic setting → Log Analytics
- **Conditional**: Use `for_each` (keyed) over `count` (indexed) for named resources
- **Identity**: SystemAssigned managed identity + RBAC; avoid keys/connection strings
- **Provider pin**: `~> 4.0` (allows 4.x patches, blocks 5.0)
- **Telemetry**: Set `enable_telemetry = false` in restricted-network environments
- **Moved blocks**: Use `moved {}` when renaming resources to prevent destroy/recreate
- **Budget**: 3 forecast thresholds (80%/100%/120%); amount and emails MUST be variables
## Steps
Applying a Terraform pattern in a root module:
1. **Identify the pattern** — match your need to a row in [Quick Reference](#quick-reference) (hub-spoke, private endpoint, diagnostics, conditional, identity, budget, plan interpretation)
2. **Load the reference** — read the linked `references/*.md`; do not load all at once
3. **Compose AVM modules** — wire outputs as inputs (see [Canonical Example](#canonical-example--module-composition)); never hardcode IDs
4. **Pin the provider** — `~> 4.0` only; do not use `>= 3.0` or exact `= 4.x.y`
5. **Add diagnostics + budget** — every resource gets a diagnostic setting; every deployment gets a budget with 80%/100%/120% forecast alerts
6. **Plan before apply** — `terraform plan -out=plan.tfplan`; review for `~`/`-`/`+/-` operations against [`references/plan-interpretation.md`](references/plan-interpretation.md)
7. **Validate** — `terraform fmt -check`, `terraform validate`, `npm run validate:terraform`, `npm run validate:iac-security-baseline`
## Gotchas
- **Set-type phantom diffs** — `azurerm_application_gateway`, `azurerm_lb`,
`azurerm_network_security_group`, `azurerm_firewall`, `azurerm_frontdoor`:
adding ONE element causes ALL elements to show `~` changes. Mitigation:
`ignore_changes` on set-type blocks.
- **Provider pin `~> 4.0` is critical** — `>= 3.0` crosses breaking
versions; `= 4.1.0` blocks patches. MUST use `~> 4.0`.
- **`for_each` over `count` for named resources** — `count` causes drift
when items are inserted/removed (Terraform reindexes).
Use `for_each = toset()`.
- **`moved` block required for renaming** — Renaming a resource ID
without a `moved {}` block causes destroy + recreate.
- **azurerm 4.x renamed attributes** —
`allow_blob_public_access` → `allow_nested_items_to_be_public`;
`enable_https_traffic_only` → `https_traffic_only_enabled`;
`azurerm_app_service` removed → use `azurerm_linux_web_app`.
---
## Reference Index
| FileGuidance for instrumenting webapps with Azure Application Insights. Provides telemetry patterns, SDK setup, and configuration references. WHEN: how to instrument app, App Insights SDK, telemetry patterns, what is App Insights, Application Insights guidance, instrumentation examples, APM best practices.
Use for Azure AI: Search, Speech, OpenAI, Document Intelligence. Helps with search, vector/hybrid search, speech-to-text, text-to-speech, transcription, OCR. WHEN: AI Search, query search, vector search, hybrid search, semantic search, speech-to-text, text-to-speech, transcribe, OCR, convert text to speech.
Configure Azure API Management as an AI Gateway for AI models, MCP tools, and agents. WHEN: semantic caching, token limit, content safety, load balancing, AI model governance, MCP rate limiting, jailbreak detection, add Azure OpenAI backend, add AI Foundry model, test AI gateway, LLM policies, configure AI backend, token metrics, AI cost control, convert API to MCP, import OpenAPI to gateway.
ROUTING SKILL — delegates to specialized diagram skills. USE FOR: any diagram request when the caller does not know which tool to use. Routes to drawio, python-diagrams, or mermaid based on diagram type.
Build and deploy GitHub Copilot SDK apps to Azure. WHEN: build copilot app, create copilot app, copilot SDK, @github/copilot-sdk, scaffold copilot project, copilot-powered app, deploy copilot app, host on azure, azure model, BYOM, bring your own model, use my own model, azure openai model, DefaultAzureCredential, self-hosted model, copilot SDK service, chat app with copilot, copilot-sdk-service template, azd init copilot, CopilotClient, createSession, sendAndWait, GitHub Models API.
Troubleshoot and resolve issues with Azure Messaging SDKs for Event Hubs and Service Bus. Covers connection failures, authentication errors, message processing issues, and SDK configuration problems. WHEN: event hub SDK error, service bus SDK issue, messaging connection failure, AMQP error, event processor host issue, message lock lost, send timeout, receiver disconnected, SDK troubleshooting, azure messaging SDK, event hub consumer, service bus queue issue, topic subscription error, enable logging event hub, service bus logging, eventhub python, servicebus java, eventhub javascript, servicebus dotnet, event hub checkpoint, event hub not receiving messages, service bus dead letter.
Authoritative reference for VS Code Copilot customization mechanisms: instructions, prompt files, custom agents, agent skills, MCP servers, hooks, and plugins. Use when deciding which customization type to use, creating new .instructions.md/.prompt.md/.agent.md/SKILL.md/mcp.json files from scratch, or debugging why a customization is not loading. DO NOT USE FOR: routine file edits where the format is already known.
Provides canonical entity counts from count-manifest.json. Use when agents need to reference how many agents, skills, instructions, or validators exist. Prevents hard-coded counts. WHEN: agent count, skill count, how many agents, how many skills, entity inventory, project statistics.