Azure Verified Modules
HashiCorpOfficialPublished by HashiCorp
- Skill
- Guidelines
- Cloud and DevOps
- MPL-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides the comprehensive set of requirements for Azure Verified Modules (AVM) certification. It outlines mandatory standards for Terraform module structure, provider configuration, code style, variable and output definitions, and testing procedures. It is designed to ensure that Azure Terraform modules maintain consistency and follow established AVM specifications.
What it does
- Defines mandatory coding standards for Terraform variables, outputs, and local values.
- Specifies required provider versions and configuration patterns for Azure modules.
- Provides a compliance checklist for module structure and documentation.
- Outlines requirements for testing tools and branch protection policies.
- Details patterns for handling breaking changes and feature toggles.
- Establishes rules for module cross-referencing and dependency management.
When to use it
- When developing new Terraform modules intended for AVM certification.
- When reviewing existing modules to ensure they meet AVM standards.
- When updating modules to comply with current Azure provider version constraints.
- When preparing a module for contribution to the Azure Verified Modules repository.
Advantages
- Ensures adherence to official AVM module specifications.
- Promotes consistent code structure across Azure infrastructure projects.
- Provides clear guidance on handling sensitive data and deprecated components.
- Includes a structured checklist to facilitate self-auditing of modules.
Usage examples
- “What are the naming conventions for variables in an AVM module?”
- The guide specifies that variables should follow HashiCorp naming rules, use lower snake_casing, and feature switches should use positive statements like xxx_enabled.
- “How should I configure provider versions in my module?”
- The guide requires using a required_providers block with specific version constraints for azurerm and azapi, typically using the pessimistic version constraint operator.
- “What is the requirement for documentation in AVM modules?”
- Documentation must be automatically generated using Terraform Docs, and a .terraform-docs.yml file must be present in the module root.
- “How do I handle optional nested objects in my Terraform code?”
- The guide mandates the use of dynamic blocks for optional nested objects to ensure proper conditional creation.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/hashicorp/azure-verified-modules/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip azure-verified-modules.zip -d .agents/skills
Documentation by HashiCorp
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"
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 versionsSHOULD 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 creationMUST use
map(xxx)orset(xxx)as resource'sfor_eachcollectionThe 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_nameProvider Declarations in Modules
Severity: MUST | Requirement: TFNFR27
providerMUST NOT be declared in modules (except forconfiguration_aliases)providerblocks in modules MUST only usealiasProvider 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 typeTarget 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 reasonsUse
boolinstead ofstring/numberfor true/false valuesUse 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.tfAnnotate with
DEPRECATEDat the beginning of descriptionDeclare 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 attributesFor 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.tfDefine new outputs in
outputs.tfClean up during major version releases
Local Values Standards
locals.tf Organization
Severity: MAY | Requirement: TFNFR31
locals.tfSHOULD only containlocalsblocksMAY 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
terraformblockFirst line MUST define
required_versionMUST 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_providersblockEach provider MUST specify
sourceandversionProviders SHOULD be sorted alphabetically
Only include directly required providers
sourceMUST be in formatnamespace/nameversionMUST include minimum and maximum major version constraintsSHOULD 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
dynamicRenaming resources without
movedblocksChanging
counttofor_eachor vice versa
Variable/Output blocks:
Deleting/renaming variables
Changing variable
typeChanging variable
defaultvaluesChanging
nullableto falseChanging
sensitivefrom false to trueAdding variables without
defaultDeleting outputs
Changing output
valueChanging 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
Files
- ATTRIBUTION.mdAdded by AutoGineer912 B
- LICENSELicence file added by AutoGineer16.3 KiB
- SKILL.md15.9 KiB
ATTRIBUTION.md
Attribution
This folder is an unmodified copy of the Agent Skill "azure-verified-modules", distributed by AutoGineer (https://autogineer.com/agent-skills).
Commit: 5e30fa5c867ba6777c37e4206babfd08049c396f
Published by: HashiCorp (https://github.com/hashicorp)
Publisher: HashiCorp (https://github.com/hashicorp)
Licence: Mozilla Public License 2.0 (https://github.com/hashicorp/agent-skills/blob/5e30fa5c867ba6777c37e4206babfd08049c396f/LICENSE)
Licence evidence: repository licence LICENSE
Retrieved: 2026-11-07
The skill's own files are unmodified copies. AutoGineer is not affiliated with or endorsed by the author or the publisher.
Files added by AutoGineer
ATTRIBUTION.md: this file, written by AutoGineer
LICENSE: copied from LICENSE
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- HashiCorp
- Publisher
- HashiCorp (Official)
- Source
- hashicorp/agent-skills · plugins/terraform/skills/azure-verified-modules · commit 5e30fa5
- Licence
- Mozilla Public License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by HashiCorp.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download azure-verified-modules.zip