Compartilhar via


Casos de teste para modelos do ARM

Este artigo descreve os testes que são executados com o kit de ferramentas de teste de modelo para modelos do ARM (modelos do Azure Resource Manager). Ele fornece exemplos de aprovação ou reprovação no teste e inclui o nome de cada teste. Para obter mais informações sobre como executar testes, ou um teste específico, confira Parâmetros de teste.

Usar o esquema correto

Nome do teste: o esquema deploymenttemplate está correto

No modelo, você deve especificar um valor de esquema válido.

O exemplo a seguir é reprovado porque o esquema é inválido.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-01-01/deploymentTemplate.json#",
}

O exemplo a seguir exibe um aviso porque a versão do esquema 2015-01-01 foi preterida e não mantida.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
}

O exemplo a seguir é aprovado usando um esquema válido.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
}

A propriedade schema do modelo deve ser definida para um dos seguintes esquemas:

  • https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json

Parâmetros declarados devem ser usados

Nome do teste: parâmetros devem ser referenciados

Este teste localiza parâmetros que não são usados no modelo ou que não são usados em uma expressão válida.

Para reduzir a confusão no modelo, exclua todos os parâmetros definidos, mas não usados. A eliminação de parâmetros não utilizados simplifica as implantações de modelos porque você não precisa fornecer valores desnecessários.

No Bicep, use a regra do Linter – sem parâmetros não utilizados.

O exemplo a seguir é reprovado porque a expressão que faz referência a um parâmetro está faltando o colchete inicial ([).

"resources": [
  {
    "location": " parameters('location')]"
  }
]

O exemplo a seguir é aprovado porque a expressão é válida.

"resources": [
  {
    "location": "[parameters('location')]"
  }
]

Parâmetros seguros não podem ter padrão embutido em código

Nome do teste: parâmetros seguros de cadeia de caracteres não podem ter padrão

Não forneça um valor padrão inserido no código para um parâmetro seguro no modelo. Um parâmetro seguro pode ter uma cadeia de caracteres vazia como valor padrão ou usar a função newGuid em uma expressão.

Você usa os tipos secureString ou secureObject em parâmetros que contêm valores confidenciais, como senhas. Quando um parâmetro usa um tipo seguro, o valor do parâmetro não é registrado ou armazenado no histórico de implantação. Essa ação impede que um usuário mal-intencionado descubra o valor confidencial.

Quando você fornece um valor padrão, esse valor é detectável por qualquer pessoa que tenha acesso ao modelo ou ao histórico de implantação.

No Bicep, use a regra do Linter – padrão de parâmetro seguro.

O exemplo a seguir é reprovado.

"parameters": {
  "adminPassword": {
    "defaultValue": "HardcodedPassword",
    "type": "secureString"
  }
}

O exemplo a seguir é aprovado.

"parameters": {
  "adminPassword": {
    "type": "secureString"
  }
}

O exemplo a seguir é aprovado porque a função newGuid é usada.

"parameters": {
  "secureParameter": {
    "type": "secureString",
    "defaultValue": "[newGuid()]"
  }
}

As URLs de ambiente não podem ser embutidas em código

Nome do teste: deploymenttemplate não deve conter URI inserido no código

Não use URLs de ambiente embutidas em código em seu modelo. Em vez disso, use a função de ambiente para obter essas URLs dinamicamente durante a implantação. Para obter uma lista dos hosts de URL que estão bloqueados, confira o caso de teste.

No Bicep, use a regra do Linter – nenhuma URL de ambiente codificada.

O exemplo a seguir é reprovado porque a URL está embutida no código.

"variables":{
  "AzureURL":"https://management.azure.com"
}

O teste também reprova quando usado com concat ou URI.

"variables":{
  "AzureSchemaURL1": "[concat('https://','gallery.azure.com')]",
  "AzureSchemaURL2": "[uri('gallery.azure.com','test')]"
}

O exemplo a seguir é aprovado.

"variables": {
  "AzureSchemaURL": "[environment().gallery]"
}

O local usa parâmetro

Nome do teste: local não deve ser inserido em código

Para definir a localização de um recurso, seus modelos devem ter um parâmetro denominado location com o tipo definido como string. No modelo principal, azuredeploy.jsno ou mainTemplate.json, esse parâmetro pode usar como padrão o local do grupo de recursos. Em modelos vinculados ou aninhados, o parâmetro de local não deve ter um local padrão.

Os usuários do modelo podem ter acesso limitado a regiões em que podem criar recursos. Um local de recurso em código pode impedir que os usuários criarem um recurso. A expressão "[resourceGroup().location]" pode bloquear usuários se o grupo de recursos foi criado em uma região que o usuário não pode acessar. Os usuários bloqueados não podem usar o modelo.

Ao fornecer um parâmetro de location que usa como padrão o local do grupo de recursos, os usuários podem usar o valor padrão quando for conveniente, mas também especificar um local diferente.

No Bicep, use a Regra linter – sem expressões de localização fora dos valores padrão do parâmetro.

O exemplo a seguir é reprovado porque o location do recurso está definido como resourceGroup().location.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[resourceGroup().location]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ]
}

O próximo exemplo usa um parâmetro location, mas é reprovado porque o padrão do parâmetro é um local embutido em código.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "westus"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

O exemplo a seguir é aprovado quando o modelo é usado como o modelo principal. Crie um parâmetro que usa como padrão o local do grupo de recursos, mas permite que os usuários forneçam um valor diferente.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for the resources."
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

Observação

Se o exemplo anterior for usado como um modelo vinculado, o teste será reprovado. Quando usado como um modelo vinculado, remova o valor padrão.

Os recursos devem ter o local

Nome do teste: recursos devem ter o local

O local de um recurso deve ser definido como uma expressão de modelo ou global. A expressão do modelo normalmente usaria o parâmetro location descrito em Locais de uso do parâmetro.

No Bicep, use a regra do Linter – nenhum local codificado.

O exemplo a seguir é reprovado porque location não é uma expressão ou global.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "functions": [],
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "westus",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

O exemplo a seguir é aprovado porque o recurso location está definido como global.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "functions": [],
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "global",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

O próximo exemplo também é aprovado porque o parâmetro location usa uma expressão. O recurso location usa o valor da expressão.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for the resources."
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

O tamanho da VM usa o parâmetro

Nome do teste: tamanho da VM deve ser um parâmetro

Não faça o embutimento em código de vmSize do hardwareProfile. O teste é reprovado quando o hardwareProfile é omitido ou contém um valor embutido em código. Forneça um parâmetro para que os usuários do modelo possam modificar o tamanho da máquina virtual implantada. Para obter mais informações, confira Microsoft.Compute virtualMachines.

O exemplo a seguir é reprovado porque o objeto vmSize de hardwareProfile é um valor embutido em código.

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "2020-12-01",
    "name": "demoVM",
    "location": "[parameters('location')]",
    "properties": {
      "hardwareProfile": {
        "vmSize": "Standard_D2_v3"
      }
    }
  }
]

O exemplo é aprovado quando um parâmetro especifica um valor para vmSize:

"parameters": {
  "vmSizeParameter": {
    "type": "string",
    "defaultValue": "Standard_D2_v3",
    "metadata": {
      "description": "Size for the virtual machine."
    }
  }
}

Em seguida, hardwareProfile usa uma expressão a fim de que vmSize faça referência ao valor do parâmetro:

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "2020-12-01",
    "name": "demoVM",
    "location": "[parameters('location')]",
    "properties": {
      "hardwareProfile": {
        "vmSize": "[parameters('vmSizeParameter')]"
      }
    }
  }
]

Os valores mínimo e máximo são números

Nome do teste: valor mínimo e máximo são números

Ao definir um parâmetro com minValue e maxValue, especifique-os como números. Você deve usar minValue e maxValue como um par ou o teste será reprovado.

O exemplo a seguir é reprovado porque minValue e maxValue são cadeias de caracteres.

"exampleParameter": {
  "type": "int",
  "minValue": "0",
  "maxValue": "10"
}

O exemplo a seguir é reprovado apenas porque minValue é usado.

"exampleParameter": {
  "type": "int",
  "minValue": 0
}

O exemplo a seguir é aprovado porque minValue e maxValue são números.

"exampleParameter": {
  "type": "int",
  "minValue": 0,
  "maxValue": 10
}

Parâmetro de artefatos definido corretamente

Nome do teste: parâmetro de artefatos

Ao incluir parâmetros para _artifactsLocation e _artifactsLocationSasToken, use os padrões e tipos corretos. As seguintes condições devem ser atendidas para passar neste teste:

  • Se você fornecer um parâmetro, deverá fornecer o outro.
  • _artifactsLocation deve ser um string.
  • _artifactsLocation deve ter um valor padrão no modelo principal.
  • _artifactsLocation não pode ter um valor padrão em um modelo aninhado.
  • _artifactsLocation deve ter "[deployment().properties.templateLink.uri]" ou a URL do repositório bruto como valor padrão.
  • _artifactsLocationSasToken deve ser um secureString.
  • _artifactsLocationSasToken só pode ter uma cadeia de caracteres vazia como valor padrão.
  • _artifactsLocationSasToken não pode ter um valor padrão em um modelo aninhado.

No Bicep, use a regra do Linter – parâmetros de artefatos.

Variáveis declaradas devem ser usadas

Nome do teste: variáveis devem ser referenciadas

Este teste localiza variáveis que não são usadas no modelo ou que não são usadas em uma expressão válida. Para reduzir a confusão no modelo, exclua todas as variáveis definidas, mas não usadas.

Variáveis que usam o elemento copy para iterar valores devem ser referenciadas. Para obter mais informações, confira Iteração de variável em modelos do ARM.

No Bicep, use a regra do Linter – nenhuma variável não utilizada.

O exemplo a seguir é reprovado porque a variável que usa o elemento copy não é referenciada.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "itemCount": {
      "type": "int",
      "defaultValue": 5
    }
  },
  "variables": {
    "copy": [
      {
        "name": "stringArray",
        "count": "[parameters('itemCount')]",
        "input": "[concat('item', copyIndex('stringArray', 1))]"
      }
    ]
  },
  "resources": [],
  "outputs": {}
}

O exemplo a seguir é reprovado porque a expressão que faz referência a uma variável está sem o colchete inicial ([).

"outputs": {
  "outputVariable": {
    "type": "string",
    "value": " variables('varExample')]"
  }
}

O exemplo a seguir é aprovado porque a variável é referenciada em outputs.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "itemCount": {
      "type": "int",
      "defaultValue": 5
    }
  },
  "variables": {
    "copy": [
      {
        "name": "stringArray",
        "count": "[parameters('itemCount')]",
        "input": "[concat('item', copyIndex('stringArray', 1))]"
      }
    ]
  },
  "resources": [],
  "outputs": {
    "arrayResult": {
      "type": "array",
      "value": "[variables('stringArray')]"
    }
  }
}

O exemplo a seguir é aprovado porque a expressão é válida.

"outputs": {
  "outputVariable": {
    "type": "string",
    "value": "[variables('varExample')]"
  }
}

A variável dinâmica não deve usar concat

Nome do teste: referências de variável dinâmica não devem usar concat

Às vezes, você precisa construir dinamicamente uma variável com base no valor de outra variável ou parâmetro. Não use a função concat ao definir o valor. Em vez disso, use um objeto que inclua as opções disponíveis e obtenha dinamicamente uma das propriedades do objeto durante a implantação.

O exemplo a seguir é aprovado. A variável currentImage é definida dinamicamente durante a implantação.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "osType": {
      "type": "string",
      "allowedValues": [
        "Windows",
        "Linux"
      ]
    }
  },
  "variables": {
    "imageOS": {
      "Windows": {
        "image": "Windows Image"
      },
      "Linux": {
        "image": "Linux Image"
      }
    },
    "currentImage": "[variables('imageOS')[parameters('osType')].image]"
  },
  "resources": [],
  "outputs": {
    "result": {
      "type": "string",
      "value": "[variables('currentImage')]"
    }
  }
}

Usar a versão recente de API

Nome do teste: apiVersions deve ser recente

A versão da API para cada recurso deve usar uma versão recente codificada como cadeia de caracteres. O teste avalia a versão da API em seu modelo em relação às versões do provedor de recursos no cache do kit de ferramentas. Uma versão da API com menos de dois anos a partir da data em que o teste foi executado é considerada recente. Não use uma versão de visualização quando uma versão mais recente estiver disponível.

Um aviso de que uma versão da API não foi encontrada apenas indica que a versão não está incluída no cache do kit de ferramentas. Usar a versão mais recente de uma API, que é recomendada, pode gerar o aviso.

Saiba mais sobre o cache do kit de ferramentas.

No Bicep, use a regra do Linter – usar versões recentes da API.

O exemplo a seguir é reprovado porque a versão da API tem mais de dois anos.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2019-06-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]"
  }
]

O exemplo a seguir é reprovado porque uma versão de visualização é usada quando uma versão mais recente está disponível.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2020-08-01-preview",
    "name": "storageaccount1",
    "location": "[parameters('location')]"
  }
]

O exemplo a seguir é aprovado porque é uma versão recente que não é de visualização.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-02-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]"
  }
]

Usar versão de API embutida em código

Nome do teste: provedores apiVersions não são permitidos

A versão de API para um tipo de recurso determina quais propriedades estão disponíveis. Forneça uma versão de API inserida em código no modelo. Não recupere uma versão da API determinada durante a implantação porque você não sabe quais propriedades estão disponíveis.

O exemplo a seguir é reprovado.

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "[providers('Microsoft.Compute', 'virtualMachines').apiVersions[0]]",
    ...
  }
]

O exemplo a seguir é aprovado.

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "2020-12-01",
    ...
  }
]

As propriedades não podem estar vazias

Nome do teste: modelo não deve conter espaços em branco

Não use propriedades embutidas em código em um valor vazio. Os valores vazios incluem cadeias de caracteres, objetos ou matrizes nulos e vazios. Se uma propriedade for definida com um valor vazio, remova-a do seu modelo. Você pode definir uma propriedade com um valor vazio durante a implantação, como por meio de um parâmetro.

A propriedade template em um modelo aninhado pode incluir propriedades vazias. Para obter mais informações sobre modelos aninhados, confira Implantações do Microsoft.Resources.

O exemplo a seguir é reprovado porque existem propriedades vazias.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-01-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]",
    "sku": {},
    "kind": ""
  }
]

O exemplo a seguir é aprovado porque as propriedades incluem valores.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-01-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]",
    "sku": {
      "name": "Standard_LRS",
      "tier": "Standard"
    },
    "kind": "Storage"
  }
]

Usar funções de ID do recurso

Nome do teste: IDs devem ser derivadas de ResourceIDs

Ao especificar uma ID do recurso, use uma das funções de ID de recurso. As funções permitidas são:

Não use a função concat para criar uma ID do recurso.

No Bicep, use a regra do Linter – usar funções de ID de recurso.

O exemplo a seguir é reprovado.

"networkSecurityGroup": {
    "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]"
}

O exemplo a seguir é aprovado.

"networkSecurityGroup": {
    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}

A função resourceId tem parâmetros corretos

Nome do teste: resourceIds não deve conter

Ao gerar IDs do recurso, não use funções desnecessárias para parâmetros opcionais. Por padrão, a função resourceId usa a assinatura e o grupo de recursos atuais. Não é necessário fornecer esses valores.

O exemplo a seguir é reprovado, pois você não precisa fornecer a ID da assinatura e o nome do grupo de recursos atuais.

"networkSecurityGroup": {
    "id": "[resourceId(subscription().subscriptionId, resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}

O exemplo a seguir é aprovado.

"networkSecurityGroup": {
    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}

Este teste se aplica a:

Para reference e list*, o teste reprova quando você usa concat para construir a ID do recurso.

Práticas recomendadas dependsOn

Nome do teste: práticas recomendadas dependsOn

Ao definir as dependências de implantação, não use a função if para testar uma condição. Se um recurso depender de outro que seja implantado condicionalmente, defina a dependência da mesma forma que você faria com qualquer recurso. Quando um recurso condicional não é implantado, o Azure Resource Manager o remove automaticamente das dependências necessárias.

O elemento dependsOn não pode começar com uma função concat.

No Bicep, use a regra do Linter – nenhuma entrada dependsOn desnecessária.

O exemplo a seguir é reprovado porque contém uma função if.

"dependsOn": [
  "[if(equals(parameters('newOrExisting'),'new'), variables('storageAccountName'), '')]"
]

O exemplo a seguir é reprovado porque começa com concat.

"dependsOn": [
  "[concat(variables('storageAccountName'))]"
]

O exemplo a seguir é aprovado.

"dependsOn": [
  "[variables('storageAccountName')]"
]

Implantações aninhadas ou vinculadas não podem usar depuração

Nome do teste: recursos de implantação não devem ser depurados

Ao definir um modelo aninhado ou vinculado com o tipo de recurso Microsoft.Resources/deployments, você pode habilitar a depuração. A depuração é usada quando você precisa testar um modelo, mas pode expor informações confidenciais. Antes que o modelo seja usado na produção, desligue a depuração. Você pode remover o objeto debugSetting ou alterar a propriedade detailLevel para none.

O exemplo a seguir é reprovado.

"debugSetting": {
  "detailLevel": "requestContent"
}

O exemplo a seguir é aprovado.

"debugSetting": {
  "detailLevel": "none"
}

Nomes de usuário administrador não podem ser valores literais

Nome do teste: adminUsername não deve ser literal

Ao definir um adminUserName, não use um valor literal. Crie um parâmetro para o nome de usuário e use uma expressão para referenciar o valor do parâmetro.

No Bicep, use a regra do Linter – o nome de usuário administrador não deve ser literal.

O exemplo a seguir é reprovado com um valor literal.

"osProfile":  {
  "adminUserName": "myAdmin"
}

O exemplo a seguir é aprovado com uma expressão.

"osProfile": {
  "adminUsername": "[parameters('adminUsername')]"
}

Usar imagem de VM mais recente

Nome do teste: imagens de VM devem usar a versão mais recente

Esse teste está desabilitado, mas a saída mostra que ele foi aprovado. A melhor prática é verificar seu modelo quanto aos seguintes critérios:

Se o modelo incluir uma máquina virtual com uma imagem, verifique se ele está usando a versão mais recente da imagem.

No Bicep, use a regra do Linter – usar imagem de VM estável.

Usar imagens de VM estáveis

Nome do teste: máquinas virtuais não devem ser pré-visualizadas

As máquinas virtuais não devem usar imagens de pré-visualização. O teste escaneia o storageProfile para verificar se o imageReference não está usando uma cadeia de caracteres contendo uma versão de visualização. E se essa versão de visualização não está sendo usada nas propriedades imageReference, offer, sku ou version.

Para obter mais informações sobre a propriedade imageReference, confira Microsoft.Compute virtualMachines e Microsoft.Compute virtualMachineScaleSets.

No Bicep, use a regra do Linter – usar imagem de VM estável.

O exemplo a seguir é aprovado porque imageReference é uma cadeia de caracteres que contém versão de visualização.

"properties": {
  "storageProfile": {
    "imageReference": "latest-preview"
  }
}

O exemplo a seguir é reprovado quando a versão de visualização é usada em offer, sku ou version.

"properties": {
  "storageProfile": {
    "imageReference": {
      "publisher": "Canonical",
      "offer": "UbuntuServer_preview",
      "sku": "16.04-LTS-preview",
      "version": "preview"
    }
  }
}

O exemplo a seguir é aprovado.

"storageProfile": {
  "imageReference": {
    "publisher": "Canonical",
    "offer": "UbuntuServer",
    "sku": "16.04-LTS",
    "version": "latest"
  }
}

Não usar a extensão ManagedIdentity

Nome do teste: ManagedIdentityExtension não deve ser usada

Não aplique a extensão ManagedIdentity a uma máquina virtual. A extensão foi preterida em 2019 e não deve mais ser usada.

As saídas não podem incluir segredos

Nome do teste: saídas não devem conter segredos

Não inclua nenhum valor na seção outputs que tenha o potencial de expor segredos. Por exemplo, parâmetros seguros do tipo secureString ou secureObject, ou funções de lista* como listKeys.

A saída de um modelo é armazenada no histórico de implantação, o que possibilita que um usuário mal-intencionado encontre essas informações.

No Bicep, use a regra do Linter – as saídas não devem conter segredos.

O exemplo a seguir é reprovado porque ele inclui um parâmetro seguro em um valor de saída.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "secureParam": {
      "type": "secureString"
    }
  },
  "functions": [],
  "variables": {},
  "resources": [],
  "outputs": {
    "badResult": {
      "type": "string",
      "value": "[concat('this is the value ', parameters('secureParam'))]"
    }
  }
}

O exemplo a seguir reprova porque ele usa uma função list* nas saídas.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageName": {
      "type": "string"
    }
  },
  "functions": [],
  "variables": {},
  "resources": [],
  "outputs": {
    "badResult": {
      "type": "object",
      "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
    }
  }
}

Usar protectedSettings para segredos commandToExecute

Nome do teste: CommandToExecute deve usar ProtectedSettings para segredos

Para recursos com o tipo CustomScript, use o protectedSettings criptografado quando commandToExecute incluir dados com segredo, como uma senha. Por exemplo, dados com segredo podem ser usados em parâmetros seguros do tipo secureString ou secureObject, funções de lista* como listKeys ou scripts personalizados.

Não use dados com segredo no objeto settings porque eles usam texto não criptografado. Para obter mais informações, confira Microsoft.Compute virtualMachines/extensions, Windows ou Linux.

No Bicep, use a regra do Linter – usar protectedSettings para segredos commandToExecute.

O exemplo a seguir é reprovado porque settings usa commandToExecute com um parâmetro seguro.

"parameters": {
  "adminPassword": {
    "type": "secureString"
  }
}
...
"properties": {
  "type": "CustomScript",
  "settings": {
    "commandToExecute": "[parameters('adminPassword')]"
  }
}

O exemplo a seguir é reprovado porque settings usa commandToExecute com uma função listKeys.

"properties": {
  "type": "CustomScript",
  "settings": {
    "commandToExecute": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
  }
}

O exemplo a seguir é aprovado porque protectedSettings usa commandToExecute com um parâmetro seguro.

"parameters": {
  "adminPassword": {
    "type": "secureString"
  }
}
...
"properties": {
  "type": "CustomScript",
  "protectedSettings": {
    "commandToExecute": "[parameters('adminPassword')]"
  }
}

O exemplo a seguir é aprovado porque protectedSettings usa commandToExecute com uma função listKeys.

"properties": {
  "type": "CustomScript",
  "protectedSettings": {
    "commandToExecute": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
  }
}

Usar versões recentes da API em funções de referência

Nome do Teste: apiVersions Deve Ser Recente em Funções de Referência

A versão da API usada em uma função de referência deve ser recente, e não uma versão de visualização. O teste avalia a versão da API em seu modelo em relação às versões do provedor de recursos no cache do kit de ferramentas. Uma versão da API com menos de dois anos a partir da data em que o teste foi executado é considerada recente.

Um aviso de que uma versão da API não foi encontrada apenas indica que a versão não está incluída no cache do kit de ferramentas. Usar a versão mais recente de uma API, que é recomendada, pode gerar o aviso.

Saiba mais sobre o cache do kit de ferramentas.

O exemplo a seguir é reprovado porque a versão da API tem mais de dois anos.

"outputs": {
  "stgAcct": {
    "type": "string",
    "value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01')]"
  }
}

O exemplo a seguir é reprovado porque a versão da API é uma versão de visualização.

"outputs": {
  "stgAcct": {
    "type": "string",
    "value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2020-08-01-preview')]"
  }
}

O exemplo a seguir é aprovado porque a versão da API tem menos de dois anos e não é uma versão de visualização.

"outputs": {
  "stgAcct": {
    "type": "string",
    "value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-02-01')]"
  }
}

Usar o tipo e o nome em funções resourceId

Nome do teste: Os Recursos não Devem ser Ambíguos

Esse teste está desabilitado, mas a saída mostra que ele foi aprovado. A melhor prática é verificar seu modelo quanto aos seguintes critérios:

Um resourceId deve incluir um tipo e nome de recurso. Este teste encontra todas as funções de resourceId do modelo e verifica se o recurso é usado no modelo com a sintaxe correta. Caso contrário, a função será considerada ambígua.

Por exemplo, uma função resourceId é considerada ambígua:

  • Quando um recurso não é encontrado no modelo e um grupo de recursos não é especificado.
  • Se um recurso incluir uma condição e um grupo de recursos não for especificado.
  • Se um recurso relacionado contiver alguns, mas não todos os segmentos de nome. Por exemplo, um recurso filho contém mais de um segmento de nome. Para obter mais informações, confira comentários sobre resourceId.

Usar o escopo interno para parâmetros seguros de implantação aninhada

Nome do teste: Parâmetros Seguros em Implantações Aninhadas

Use o objeto expressionEvaluationOptions do modelo aninhado com escopo inner para avaliar expressões que contêm parâmetros seguros do tipo secureString ou secureObject ou funções de lista* como listKeys. Se o escopo outer for usado, as expressões serão avaliadas em texto não criptografado dentro do escopo do modelo pai. O valor seguro fica visível para qualquer pessoa com acesso ao histórico de implantação. O valor padrão de expressionEvaluationOptions é outer.

Para obter mais informações sobre modelos aninhados, confira Implantações do Microsoft.Resources e Escopo de avaliação de expressão em modelos aninhados.

No Bicep, use a regra do Linter – proteger parâmetros na implantação aninhada.

O exemplo a seguir é reprovado porque expressionEvaluationOptions usa o escopo outer para avaliar parâmetros seguros ou funções list*.

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2021-04-01",
    "name": "nestedTemplate",
    "properties": {
      "expressionEvaluationOptions": {
        "scope": "outer"
      }
    }
  }
]

O exemplo a seguir é aprovado porque expressionEvaluationOptions usa o escopo inner para avaliar parâmetros seguros ou funções list*.

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2021-04-01",
    "name": "nestedTemplate",
    "properties": {
      "expressionEvaluationOptions": {
        "scope": "inner"
      }
    }
  }
]

Próximas etapas