
azure-verified-modules
Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules that need AVM certification.
- Installs
- 3.3K
- Last 24h
- +17
- Trending rank
- #6502
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/hashicorp/agent-skills --skill azure-verified-modules- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads azure-verified-modules automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Azure Verified Modules (AVM) Requirements
This guide covers the mandatory requirements for Azure Verified Modules certification. These requirements ensure consistency, quality, and maintainability across Azure Terraform modules.
References:
Table of Contents
- Module Cross-Referencing
- Azure Provider Requirements
- Code Style Standards
- Variable Requirements
- Output Requirements
- Local Values Standards
- Terraform Configuration Requirements
- Testing Requirements
- Documentation Requirements
- Breaking Changes & Feature Management
- Contribution Standards
- Compliance Checklist
Module Cross-Referencing
Severity: MUST | Requirement: TFFR1
When building Resource or Pattern modules, module owners MAY cross-reference other modules. However:
- Modules MUST be referenced using HashiCorp Terraform registry reference to a pinned version
- Example:
source = "Azure/xxx/azurerm"withversion = "1.2.3"
- Example:
- Modules MUST NOT use git references (e.g.,
git::https://xxx.yyy/xxx.gitorgithub.com/xxx/yyy) - Modules MUST NOT contain references to non-AVM modules
Azure Provider Requirements
Severity: MUST | Requirement: TFFR3
Authors MUST only use the following Azure providers:
| Provider | Min Version | Max Version |
|---|---|---|
| azapi | >= 2.0 | < 3.0 |
| azurerm | >= 4.0 | < 5.0 |
Requirements:
- Authors MAY select either Azurerm, Azapi, or both providers
- MUST use
required_providersblock to enforce provider versions - SHOULD use pessimistic version constraint operator (
~>)
Example:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
azapi = {
source = "Azure/azapi"
version = "~> 2.0"
}
}
}
Code Style Standards
Lower snake_casing
Severity: MUST | Requirement: TFNFR4
MUST use lower snake_casing for:
- Locals
- Variables
- Outputs
- Resources (symbolic names)
- Modules (symbolic names)
Example: snake_casing_example
Resource & Data Source Ordering
Severity: SHOULD | Requirement: TFNFR6
- Resources that are depended on SHOULD come first
- Resources with dependencies SHOULD be defined close to each other
Count & for_each Usage
Severity: MUST | Requirement: TFNFR7
- Use
countfor conditional resource creation - MUST use
map(xxx)orset(xxx)as resource'sfor_eachcollection - The map's key or set's element MUST be static literals
Example:
resource "azurerm_subnet" "pair" {
for_each = var.subnet_map # map(string)
name = "${each.value}-pair"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.1.0/24"]
}
Resource & Data Block Internal Ordering
Severity: SHOULD | Requirement: TFNFR8
Order within resource/data blocks:
-
Meta-arguments (top):
providercountfor_each
-
Arguments/blocks (middle, alphabetical):
- Required arguments
- Optional arguments
- Required nested blocks
- Optional nested blocks
-
Meta-arguments (bottom):
depends_onlifecycle(with sub-order:create_before_destroy,ignore_changes,prevent_destroy)
Separate sections with blank lines.
Module Block Ordering
Severity: SHOULD | Requirement: TFNFR9
Order within module blocks:
-
Top meta-arguments:
sourceversioncountfor_each
-
Arguments (alphabetical):
- Required arguments
- Optional arguments
-
Bottom meta-arguments:
depends_onproviders
Lifecycle ignore_changes Syntax
Severity: MUST | Requirement: TFNFR10
The ignore_changes attribute MUST NOT be enclosed in double quotes.
Good:
lifecycle {
ignore_changes = [tags]
}
Bad:
lifecycle {
ignore_changes = ["tags"]
}
Null Comparison for Conditional Creation
Severity: SHOULD | Requirement: TFNFR11
For parameters requiring conditional resource creation, wrap with object type to avoid "known after apply" issues during plan stage.
Recommended:
variable "security_group" {
type = object({
id = string
})
default = null
}
Dynamic Blocks for Optional Nested Objects
Severity: MUST | Requirement: TFNFR12
Nested blocks under conditions MUST use this pattern:
dynamic "identity" {
for_each = <condition> ? [<some_item>] : []
content {
# block content
}
}
Default Values with coalesce/try
Severity: SHOULD | Requirement: TFNFR13
Good:
coalesce(var.new_network_security_group_name, "${var.subnet_name}-nsg")
Bad:
var.new_network_security_group_name == null ? "${var.subnet_name}-nsg" : var.new_network_security_group_name
Provider Declarations in Modules
Severity: MUST | Requirement: TFNFR27
providerMUST NOT be declared in modules (except forconfiguration_aliases)providerblocks in modules MUST only usealias- Provider configurations SHOULD be passed in by module users
Variable Requirements
Not Allowed Variables
Severity: MUST | Requirement: TFNFR14
Module owners MUST NOT add variables like enabled or module_depends_on to control entire module operation. Boolean feature toggles for specific resources are acceptable.
Variable Definition Order
Severity: SHOULD | Requirement: TFNFR15
Variables SHOULD follow this order:
- All required fields (alphabetical)
- All optional fields (alphabetical)
Variable Naming Rules
Severity: SHOULD | Requirement: TFNFR16
- Follow HashiCorp's naming rules
- Feature switches SHOULD use positive statements:
xxx_enabledinstead ofxxx_disabled
Variables with Descriptions
Severity: SHOULD | Requirement: TFNFR17
descriptionSHOULD precisely describe the parameter's purpose and expected data type- Target audience is module users, not developers
- For
objecttypes, use HEREDOC format
Variables with Types
Severity: MUST | Requirement: TFNFR18
typeMUST be defined for every variabletypeSHOULD be as precise as possibleanyMAY only be used with adequate reasons- Use
boolinstead ofstring/numberfor true/false values - Use concrete
objectinstead ofmap(any)
Sensitive Data Variables
Severity: SHOULD | Requirement: TFNFR19
If a variable's type is object and contains sensitive fields, the entire variable SHOULD be sensitive = true, or extract sensitive fields into separate variables.
Non-Nullable Defaults for Collections
Severity: SHOULD | Requirement: TFNFR20
Nullable SHOULD be set to false for collection values (sets, maps, lists) when using them in loops. For scalar values, null may have semantic meaning.
Discourage Nullability by Default
Severity: MUST | Requirement: TFNFR21
nullable = true MUST be avoided unless there's a specific semantic need for null values.
Avoid sensitive = false
Severity: MUST | Requirement: TFNFR22
sensitive = false MUST be avoided (this is the default).
Sensitive Default Value Conditions
Severity: MUST | Requirement: TFNFR23
A default value MUST NOT be set for sensitive inputs (e.g., default passwords).
Handling Deprecated Variables
Severity: MUST | Requirement: TFNFR24
- Move deprecated variables to
deprecated_variables.tf - Annotate with
DEPRECATEDat the beginning of description - Declare the replacement's name
- Clean up during major version releases
Output Requirements
Additional Terraform Outputs
Severity: SHOULD | Requirement: TFFR2
Authors SHOULD NOT output entire resource objects as these may contain sensitive data and the schema can change with API or provider versions.
Best Practices:
- Output computed attributes of resources as discrete outputs (anti-corruption layer pattern)
- SHOULD NOT output values that are already inputs (except
name) - Use
sensitive = truefor sensitive attributes - For resources deployed with
for_each, output computed attributes in a map structure
Examples:
# Single resource computed attribute
output "foo" {
description = "MyResource foo attribute"
value = azurerm_resource_myresource.foo
}
# for_each resources
output "childresource_foos" {
description = "MyResource children's foo attributes"
value = {
for key, value in azurerm_resource_mychildresource : key => value.foo
}
}
# Sensitive output
output "bar" {
description = "MyResource bar attribute"
value = azurerm_resource_myresource.bar
sensitive = true
}
Sensitive Data Outputs
Severity: MUST | Requirement: TFNFR29
Outputs containing confidential data MUST be declared with sensitive = true.
Handling Deprecated Outputs
Severity: MUST | Requirement: TFNFR30
- Move deprecated outputs to
deprecated_outputs.tf - Define new outputs in
outputs.tf - Clean up during major version releases
Local Values Standards
locals.tf Organization
Severity: MAY | Requirement: TFNFR31
locals.tfSHOULD only containlocalsblocks- MAY declare
localsblocks next to resources for advanced scenarios
Alphabetical Local Arrangement
Severity: MUST | Requirement: TFNFR32
Expressions in locals blocks MUST be arranged alphabetically.
Precise Local Types
Severity: SHOULD | Requirement: TFNFR33
Use precise types (e.g., number for age, not string).
Terraform Configuration Requirements
Terraform Version Requirements
Severity: MUST | Requirement: TFNFR25
terraform.tf requirements:
- MUST contain only one
terraformblock - First line MUST define
required_version - MUST include minimum version constraint
- MUST include maximum major version constraint
- SHOULD use
~> #.#or>= #.#.#, < #.#.#format
Example:
terraform {
required_version = "~> 1.6"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}
Providers in required_providers
Severity: MUST | Requirement: TFNFR26
terraformblock MUST containrequired_providersblock- Each provider MUST specify
sourceandversion - Providers SHOULD be sorted alphabetically
- Only include directly required providers
sourceMUST be in formatnamespace/nameversionMUST include minimum and maximum major version constraints- SHOULD use
~> #.#or>= #.#.#, < #.#.#format
Testing Requirements
Test Tooling
Severity: MUST | Requirement: TFNFR5
Required testing tools for AVM:
- Terraform (
terraform validate/fmt/test) - terrafmt
- Checkov
- tflint (with azurerm ruleset)
- Go (optional for custom tests)
Test Provider Configuration
Severity: SHOULD | Requirement: TFNFR36
For robust testing, prevent_deletion_if_contains_resources SHOULD be explicitly set to false in test provider configurations.
Documentation Requirements
Module Documentation Generation
Severity: MUST | Requirement: TFNFR2
- Documentation MUST be automatically generated via Terraform Docs
- A
.terraform-docs.ymlfile MUST be present in the module root
Breaking Changes & Feature Management
Using Feature Toggles
Severity: MUST | Requirement: TFNFR34
New resources added in minor/patch versions MUST have a toggle variable to avoid creation by default:
variable "create_route_table" {
type = bool
default = false
nullable = false
}
resource "azurerm_route_table" "this" {
count = var.create_route_table ? 1 : 0
# ...
}
Reviewing Potential Breaking Changes
Severity: MUST | Requirement: TFNFR35
Breaking changes requiring caution:
Resource blocks:
- Adding new resource without conditional creation
- Adding arguments with non-default values
- Adding nested blocks without
dynamic - Renaming resources without
movedblocks - Changing
counttofor_eachor vice versa
Variable/Output blocks:
- Deleting/renaming variables
- Changing variable
type - Changing variable
defaultvalues - Changing
nullableto false - Changing
sensitivefrom false to true - Adding variables without
default - Deleting outputs
- Changing output
value - Changing output
sensitivevalue
Contribution Standards
GitHub Repository Branch Protection
Severity: MUST | Requirement: TFNFR3
Module owners MUST set branch protection policies on the default branch (typically main):
- Require Pull Request before merging
- Require approval of most recent reviewable push
- Dismiss stale PR approvals when new commits are pushed
- Require linear history
- Prevent force pushes
- Not allow deletions
- Require CODEOWNERS review
- No bypassing settings allowed
- Enforce for administrators
Compliance Checklist
Use this checklist when developing or reviewing Azure Verified Modules:
Module Structure
- Module cross-references use registry sources with pinned versions
- Azure providers (azurerm/azapi) versions meet AVM requirements
-
.terraform-docs.ymlpresent in module root - CODEOWNERS file present
Code Style
- All names use lower snake_casing
- Resources ordered with dependencies first
-
for_eachusesmap()orset()with static keys - Resource/data/module blocks follow proper internal ordering
-
ignore_changesnot quoted - Dynamic blocks used for conditional nested objects
-
coalesce()ortry()used for default values
Variables
- No
enabledormodule_depends_onvariables - Variables ordered: required (alphabetical) then optional (alphabetical)
- All variables have precise types (avoid
any) - All variables have descriptions
- Collections have
nullable = false - No
sensitive = falsedeclarations - No default values for sensitive inputs
- Deprecated variables moved to
deprecated_variables.tf
Outputs
- Outputs use anti-corruption layer pattern (discrete attributes)
- Sensitive outputs marked
sensitive = true - Deprecated outputs moved to
deprecated_outputs.tf
Terraform Configuration
-
terraform.tfhas version constraints (~>format) -
required_providersblock present with all providers - No
providerdeclarations in module (except aliases) - Locals arranged alphabetically
Testing & Quality
- Required testing tools configured
- New resources have feature toggles
- Breaking changes reviewed and documented
Summary Statistics
- Functional Requirements: 3
- Non-Functional Requirements: 34
- Total Requirements: 37
By Severity
- MUST: 21 requirements
- SHOULD: 14 requirements
- MAY: 2 requirements
Based on: Azure Verified Modules - Terraform Requirements
FAQ
What does the azure-verified-modules skill do?
Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules that need AVM certification.
How do I install azure-verified-modules?
Run npx skills add https://github.com/hashicorp/agent-skills --skill azure-verified-modules in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/azure-verified-modules/ (personal) or .claude/skills/azure-verified-modules/ (project).
Which AI agents can use azure-verified-modules?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is azure-verified-modules safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains azure-verified-modules?
It is published by hashicorp in hashicorp/agent-skills, and it is an official skill from the maker of the technology it covers. It has 3,309 recorded installs.
More from hashicorp/agent-skills
terraform-style-guide
hashicorp/agent-skills
Generate Terraform HCL code following HashiCorp's official style conventions and best practices. Use when writing, reviewing, or generating Terraform configurations.
terraform-test
hashicorp/agent-skills
Comprehensive guide for writing and running Terraform tests. Use when creating test files (.tftest.hcl), writing test scenarios with run blocks, validating infrastructure behavior with assertions, mocking providers and data sources, testing module outputs and resource configurations, or troubleshooting Terraform test syntax and execution.
refactor-module
hashicorp/agent-skills
Transform monolithic Terraform configurations into reusable, maintainable modules following HashiCorp's module design principles and community best practices.
terraform-stacks
hashicorp/agent-skills
Comprehensive guide for working with HashiCorp Terraform Stacks. Use when creating, modifying, or validating Terraform Stack configurations (.tfcomponent.hcl, .tfdeploy.hcl files), working with stack components and deployments from local modules, public registry, or private registry sources, managing multi-region or multi-environment infrastructure, or troubleshooting Terraform Stacks syntax and structure.
terraform-search-import
hashicorp/agent-skills
Discover existing cloud resources using Terraform Search queries and bulk import them into Terraform management. Use when bringing unmanaged infrastructure under Terraform control, auditing cloud resources, or migrating to IaC.
provider-resources
hashicorp/agent-skills
Implement Terraform Provider resources and data sources using the Plugin Framework: CRUD operations, schema design, plan modifiers and validators, not-found handling, waiters for eventually consistent APIs, import support, resource design principles, and required acceptance test coverage. Use when adding or changing a resource or data source, deciding whether an API concept should be a resource, wiring a resource to the provider's configured client, handling drift or resource-not-found, or reviewing a resource implementation before submission.
Popular devops & cloud skills
microsoft-foundry
microsoft/azure-skills
Build, deploy, evaluate, optimize, fine-tune, and manage Microsoft Foundry agents, models, and resources end to end. USE FOR: foundry, azd ai agent, azd provision/deploy, hosted agent scaffold/develop/run/deploy/troubleshoot, prompt agent create, managed harness agent create, GitHub Copilot harness agent, create agent, update agent, add tool to agent, invoke agent, agent insights, evaluate agent, batch eval, continuous eval, continuous monitoring, agent CI/CD, optimize prompt, improve prompt, optimize agent instructions, Agent Optimizer scaffold, dataset curation from traces, deploy model, model fine-tuning (SFT/DPO/RFT), Foundry project, RBAC, role assignment, permissions, quota, capacity, region, deployment failure, AI Services, create Foundry resource, knowledge index, customize deployment, onboard, availability, training-data, grader, distillation, large file upload. DO NOT USE FOR: Azure Functions, App Service, general Azure deploy (use azure-deploy), general Azure prep (use azure
azure-diagnostics
microsoft/azure-skills
Debug Azure production issues on Azure using AppLens, Azure Monitor, resource health, and safe triage. WHEN: debug production issues, troubleshoot app service, app service high CPU, app service deployment failure, troubleshoot container apps, container app 503 or target port mismatch, troubleshoot functions, function telemetry missing or stopped after a config/connection-string change, troubleshoot AKS, VM RDP, Linux SSH, VM black screen, can't connect to VM, reset VM password, NSG or firewall blocking, kubectl cannot connect, kube-system/CoreDNS failures, pod pending, crashloop, node not ready, upgrade failures, analyze logs, KQL, insights, image pull failures, cold start issues, health probe failures, resource health, root cause of errors, troubleshoot event hubs, troubleshoot service bus, messaging SDK error, AMQP connection failure, message lock lost, lock renewal during long-running processing, service bus dead letter.
azure-prepare
microsoft/azure-skills
Prepare azd-based Azure projects for deployment: generates azure.yaml, infrastructure (Bicep/Terraform), and Dockerfiles for the Azure Developer CLI (azd) workflow. USE ONLY when the user explicitly wants to use azd as the deployment tool, or the project already has an azure.yaml file. DO NOT USE FOR: non-azd deployments, Python App Service code-only deploys (use python-appservice-deploy), or cross-cloud migration (use azure-cloud-migrate). WHEN: prepare app for azd, create azure.yaml, set up azd infrastructure, modernize app for Azure with azd, deploy with azd, function app, timer trigger, service bus trigger, event-driven function, managed identity, generate Bicep, generate Terraform, create and deploy to Azure.
azure-ai
microsoft/azure-skills
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.
azure-deploy
microsoft/azure-skills
Execute Azure deployments for ALREADY-PREPARED applications that have existing .azure/deployment-plan.md and infrastructure files. DO NOT use this skill when the user asks to CREATE a new application — use azure-prepare instead. This skill runs azd up, azd deploy, terraform apply, and az deployment commands with built-in error recovery. Requires .azure/deployment-plan.md from azure-prepare and validated status from azure-validate. WHEN: "run azd up", "run azd deploy", "execute deployment", "push to production", "push to cloud", "go live", "ship it", "bicep deploy", "terraform apply", "publish to Azure", "launch on Azure". DO NOT USE WHEN: "create and deploy", "build and deploy", "create a new app", "set up infrastructure", "create and deploy to Azure using Terraform" — use azure-prepare for these.
azure-validate
microsoft/azure-skills
Pre-deployment validation for Azure readiness. Run deep checks on configuration, infrastructure (Bicep or Terraform), RBAC role assignments, managed identity permissions, and prerequisites before deploying. WHEN: validate my app, check deployment readiness, run preflight checks, verify configuration, check if ready to deploy, validate azure.yaml, validate Bicep, test before deploying, troubleshoot deployment errors, validate Azure Functions, validate function app, validate serverless deployment, verify RBAC roles, check role assignments, review managed identity permissions, what-if analysis, validate Container Apps deployment.