azure-verified-modules by hashicorp/agent-skills
npx skills add https://github.com/hashicorp/agent-skills --skill azure-verified-modules本指南涵盖了 Azure Verified Modules 认证的强制性要求。这些要求确保 Azure Terraform 模块的一致性、质量和可维护性。
参考资料:
严重性: 必须 | 要求: TFFR1
在构建资源或模式模块时,模块所有者可以交叉引用其他模块。但是:
source = "Azure/xxx/azurerm" 并指定 version = "1.2.3"广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
git::https://xxx.yyy/xxx.git 或 github.com/xxx/yyy)严重性: 必须 | 要求: TFFR3
作者必须仅使用以下 Azure providers:
| Provider | 最低版本 | 最高版本 |
|---|---|---|
| azapi | >= 2.0 | < 3.0 |
| azurerm | >= 4.0 | < 5.0 |
要求:
required_providers 块来强制执行 provider 版本~>)示例:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
azapi = {
source = "Azure/azapi"
version = "~> 2.0"
}
}
}
严重性: 必须 | 要求: TFNFR4
必须对以下内容使用下划线蛇形命名法:
示例:snake_casing_example
严重性: 应该 | 要求: TFNFR6
严重性: 必须 | 要求: TFNFR7
count 进行条件性资源创建map(xxx) 或 set(xxx) 作为资源的 for_each 集合示例:
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"]
}
严重性: 应该 | 要求: TFNFR8
资源/数据块内部顺序:
元参数(顶部) :
providercountfor_each参数/块(中部,按字母顺序) :
元参数(底部) :
depends_onlifecycle(子顺序:create_before_destroy、ignore_changes、prevent_destroy)各部分之间用空行分隔。
严重性: 应该 | 要求: TFNFR9
模块块内部顺序:
顶部元参数 :
sourceversioncountfor_each参数(按字母顺序) :
底部元参数 :
depends_onproviders严重性: 必须 | 要求: TFNFR10
ignore_changes 属性不得用双引号括起来。
正确:
lifecycle {
ignore_changes = [tags]
}
错误:
lifecycle {
ignore_changes = ["tags"]
}
严重性: 应该 | 要求: TFNFR11
对于需要条件性创建资源的参数,使用 object 类型包装,以避免计划阶段出现“应用后才知道”的问题。
推荐:
variable "security_group" {
type = object({
id = string
})
default = null
}
严重性: 必须 | 要求: TFNFR12
条件性嵌套块必须使用以下模式:
dynamic "identity" {
for_each = <condition> ? [<some_item>] : []
content {
# block content
}
}
严重性: 应该 | 要求: TFNFR13
正确:
coalesce(var.new_network_security_group_name, "${var.subnet_name}-nsg")
错误:
var.new_network_security_group_name == null ? "${var.subnet_name}-nsg" : var.new_network_security_group_name
严重性: 必须 | 要求: TFNFR27
provider(configuration_aliases 除外)provider 块必须仅使用 alias严重性: 必须 | 要求: TFNFR14
模块所有者不得添加如 enabled 或 module_depends_on 之类的变量来控制整个模块的运行。用于特定资源的布尔功能开关是可接受的。
严重性: 应该 | 要求: TFNFR15
变量应该遵循以下顺序:
严重性: 应该 | 要求: TFNFR16
xxx_enabled 而不是 xxx_disabled严重性: 应该 | 要求: TFNFR17
description应该精确描述参数的目的和预期的数据类型object 类型,使用 HEREDOC 格式严重性: 必须 | 要求: TFNFR18
typetype应该尽可能精确any可以仅在理由充分时使用bool 而不是 string/numberobject 而不是 map(any)严重性: 应该 | 要求: TFNFR19
如果变量的类型是 object 且包含敏感字段,则整个变量应该设为 sensitive = true,或者将敏感字段提取到单独的变量中。
严重性: 应该 | 要求: TFNFR20
对于在循环中使用的集合值(集合、映射、列表),可空性应该设为 false。对于标量值,空值可能具有语义含义。
严重性: 必须 | 要求: TFNFR21
必须避免使用 nullable = true,除非对空值有特定的语义需求。
严重性: 必须 | 要求: TFNFR22
必须避免使用 sensitive = false(这是默认值)。
严重性: 必须 | 要求: TFNFR23
敏感输入(例如默认密码)不得设置默认值。
严重性: 必须 | 要求: TFNFR24
deprecated_variables.tfDEPRECATED 标注严重性: 应该 | 要求: TFFR2
作者不应该输出整个资源对象,因为这些可能包含敏感数据,并且模式可能随 API 或 provider 版本而改变。
最佳实践:
name 除外)sensitive = truefor_each 部署的资源,以映射结构输出计算属性示例:
# 单个资源的计算属性
output "foo" {
description = "MyResource foo attribute"
value = azurerm_resource_myresource.foo
}
# for_each 资源
output "childresource_foos" {
description = "MyResource children's foo attributes"
value = {
for key, value in azurerm_resource_mychildresource : key => value.foo
}
}
# 敏感输出
output "bar" {
description = "MyResource bar attribute"
value = azurerm_resource_myresource.bar
sensitive = true
}
严重性: 必须 | 要求: TFNFR29
包含机密数据的输出必须声明为 sensitive = true。
严重性: 必须 | 要求: TFNFR30
deprecated_outputs.tfoutputs.tf 中定义新的输出严重性: 可以 | 要求: TFNFR31
locals.tf应该仅包含 locals 块locals 块声明在资源旁边严重性: 必须 | 要求: TFNFR32
locals 块中的表达式必须按字母顺序排列。
严重性: 应该 | 要求: TFNFR33
使用精确的类型(例如,年龄用 number,而不是 string)。
严重性: 必须 | 要求: TFNFR25
terraform.tf 要求:
terraform 块required_version~> #.# 或 >= #.#.#, < #.#.# 格式示例:
terraform {
required_version = "~> 1.6"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}
严重性: 必须 | 要求: TFNFR26
terraform 块必须包含 required_providers 块source 和 versionsource必须是 namespace/name 格式version必须包含最低和最高主版本约束~> #.# 或 >= #.#.#, < #.#.# 格式严重性: 必须 | 要求: TFNFR5
AVM 所需的测试工具:
terraform validate/fmt/test)严重性: 应该 | 要求: TFNFR36
为了进行稳健的测试,在测试 provider 配置中,prevent_deletion_if_contains_resources应该显式设置为 false。
严重性: 必须 | 要求: TFNFR2
.terraform-docs.yml 文件严重性: 必须 | 要求: TFNFR34
在次要/补丁版本中添加的新资源必须有一个开关变量,以默认不创建:
variable "create_route_table" {
type = bool
default = false
nullable = false
}
resource "azurerm_route_table" "this" {
count = var.create_route_table ? 1 : 0
# ...
}
严重性: 必须 | 要求: TFNFR35
需要谨慎处理的破坏性变更:
资源块:
dynamic 的嵌套块moved 块count 改为 for_each 或反之变量/输出块:
typedefault 值nullable 改为 falsesensitive 从 false 改为 truedefault 的变量valuesensitive 值严重性: 必须 | 要求: TFNFR3
模块所有者必须在默认分支(通常是 main)上设置分支保护策略:
开发或审查 Azure Verified Modules 时使用此检查清单:
.terraform-docs.yml 文件for_each 使用 map() 或 set() 并具有静态键ignore_changes 不加引号coalesce() 或 try()enabled 或 module_depends_on 变量any)nullable = falsesensitive = false 声明deprecated_variables.tfsensitive = truedeprecated_outputs.tfterraform.tf 具有版本约束(~> 格式)required_providers 块并包含所有 providersprovider 声明(别名除外)基于:Azure Verified Modules - Terraform 要求
每周安装次数
488
仓库
GitHub 星标数
481
首次出现
Jan 26, 2026
安全审计
安装于
github-copilot396
opencode377
gemini-cli368
codex363
cursor316
claude-code314
This guide covers the mandatory requirements for Azure Verified Modules certification. These requirements ensure consistency, quality, and maintainability across Azure Terraform modules.
References:
Severity: MUST | Requirement: TFFR1
When building Resource or Pattern modules, module owners MAY cross-reference other modules. However:
source = "Azure/xxx/azurerm" with version = "1.2.3"git::https://xxx.yyy/xxx.git or github.com/xxx/yyy)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:
required_providers block to enforce provider versions~>)Example:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
azapi = {
source = "Azure/azapi"
version = "~> 2.0"
}
}
}
Severity: MUST | Requirement: TFNFR4
MUST use lower snake_casing for:
Example: snake_casing_example
Severity: SHOULD | Requirement: TFNFR6
Severity: MUST | Requirement: TFNFR7
count for conditional resource creationmap(xxx) or set(xxx) as resource's for_each collectionExample:
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"]
}
Severity: SHOULD | Requirement: TFNFR8
Order within resource/data blocks:
Meta-arguments (top) :
providercountfor_eachArguments/blocks (middle, alphabetical) :
Meta-arguments (bottom) :
depends_onlifecycle (with sub-order: create_before_destroy, ignore_changes, )Separate sections with blank lines.
Severity: SHOULD | Requirement: TFNFR9
Order within module blocks:
Top meta-arguments :
sourceversioncountfor_eachArguments (alphabetical) :
Bottom meta-arguments :
depends_onprovidersSeverity: MUST | Requirement: TFNFR10
The ignore_changes attribute MUST NOT be enclosed in double quotes.
Good:
lifecycle {
ignore_changes = [tags]
}
Bad:
lifecycle {
ignore_changes = ["tags"]
}
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
}
Severity: MUST | Requirement: TFNFR12
Nested blocks under conditions MUST use this pattern:
dynamic "identity" {
for_each = <condition> ? [<some_item>] : []
content {
# block content
}
}
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
Severity: MUST | Requirement: TFNFR27
provider MUST NOT be declared in modules (except for configuration_aliases)provider blocks in modules MUST only use aliasSeverity: 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.
Severity: SHOULD | Requirement: TFNFR15
Variables SHOULD follow this order:
Severity: SHOULD | Requirement: TFNFR16
xxx_enabled instead of xxx_disabledSeverity: SHOULD | Requirement: TFNFR17
description SHOULD precisely describe the parameter's purpose and expected data typeobject types, use HEREDOC formatSeverity: MUST | Requirement: TFNFR18
type MUST be defined for every variabletype SHOULD be as precise as possibleany MAY only be used with adequate reasonsbool instead of string/number for true/false valuesobject instead of map(any)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.
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.
Severity: MUST | Requirement: TFNFR21
nullable = true MUST be avoided unless there's a specific semantic need for null values.
Severity: MUST | Requirement: TFNFR22
sensitive = false MUST be avoided (this is the default).
Severity: MUST | Requirement: TFNFR23
A default value MUST NOT be set for sensitive inputs (e.g., default passwords).
Severity: MUST | Requirement: TFNFR24
deprecated_variables.tfDEPRECATED at the beginning of descriptionSeverity: 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:
name)sensitive = true for sensitive attributesfor_each, output computed attributes in a map structureExamples:
# 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
}
Severity: MUST | Requirement: TFNFR29
Outputs containing confidential data MUST be declared with sensitive = true.
Severity: MUST | Requirement: TFNFR30
deprecated_outputs.tfoutputs.tfSeverity: MAY | Requirement: TFNFR31
locals.tf SHOULD only contain locals blockslocals blocks next to resources for advanced scenariosSeverity: MUST | Requirement: TFNFR32
Expressions in locals blocks MUST be arranged alphabetically.
Severity: SHOULD | Requirement: TFNFR33
Use precise types (e.g., number for age, not string).
Severity: MUST | Requirement: TFNFR25
terraform.tf requirements:
terraform blockrequired_version~> #.# or >= #.#.#, < #.#.# formatExample:
terraform {
required_version = "~> 1.6"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}
Severity: MUST | Requirement: TFNFR26
terraform block MUST contain required_providers blocksource and versionsource MUST be in format namespace/nameversion MUST include minimum and maximum major version constraints~> #.# or >= #.#.#, < #.#.# formatSeverity: MUST | Requirement: TFNFR5
Required testing tools for AVM:
terraform validate/fmt/test)Severity: SHOULD | Requirement: TFNFR36
For robust testing, prevent_deletion_if_contains_resources SHOULD be explicitly set to false in test provider configurations.
Severity: MUST | Requirement: TFNFR2
.terraform-docs.yml file MUST be present in the module rootSeverity: 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
# ...
}
Severity: MUST | Requirement: TFNFR35
Breaking changes requiring caution:
Resource blocks:
dynamicmoved blockscount to for_each or vice versaVariable/Output blocks:
typedefault valuesnullable to falsesensitive from false to truedefaultvaluesensitive valueSeverity: MUST | Requirement: TFNFR3
Module owners MUST set branch protection policies on the default branch (typically main):
Use this checklist when developing or reviewing Azure Verified Modules:
.terraform-docs.yml present in module rootfor_each uses map() or set() with static keysignore_changes not quotedcoalesce() or try() used for default valuesenabled or module_depends_on variablesany)nullable = falsesensitive = false declarationsdeprecated_variables.tfsensitive = truedeprecated_outputs.tfterraform.tf has version constraints (~> format)required_providers block present with all providersprovider declarations in module (except aliases)Based on: Azure Verified Modules - Terraform Requirements
Weekly Installs
488
Repository
GitHub Stars
481
First Seen
Jan 26, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot396
opencode377
gemini-cli368
codex363
cursor316
claude-code314
LLM提示词缓存优化指南:降低90%成本,实现多级缓存与语义匹配
323 周安装
小红书内容转换器:一键将通用文章转为小红书爆款笔记格式 | AI写作助手
323 周安装
内容摘要AI工具:智能提取YouTube、网页、PDF和推文内容,支持测验学习和深度探索
324 周安装
Notion知识捕获工具 - 将对话笔记自动转化为结构化Notion页面 | 知识管理自动化
324 周安装
现代Angular最佳实践指南:TypeScript严格性、信号响应式、性能优化与测试
324 周安装
iOS VoIP 通话开发:CallKit + PushKit 集成原生通话 UI 指南
324 周安装
prevent_destroy