Casos de teste para modelos ARM

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

Usar esquema correto

Nome do teste: O esquema DeploymentTemplate está correto

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

O exemplo a seguir falha 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 2015-01-01 do esquema foi preterida e não foi mantida.

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

O exemplo a seguir passa usando um esquema válido.

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

A propriedade do schema modelo deve ser definida como 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

Devem ser utilizados parâmetros declarados

Nome do teste: Os parâmetros devem ser referenciados

Este teste localiza parâmetros que não são usados no modelo ou parâmetros 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 modelo porque você não precisa fornecer valores desnecessários.

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

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

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

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

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

Os parâmetros seguros não podem ter padrão codificado

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

Não forneça um valor padrão codificado para um parâmetro seguro em seu modelo. Um parâmetro seguro pode ter uma cadeia de caracteres vazia como um 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 pode ser descoberto por qualquer pessoa que possa acessar o modelo ou o histórico de implantação.

No Bicep, use a regra Linter - parâmetro seguro padrão.

O exemplo a seguir falha.

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

O próximo exemplo passa.

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

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

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

As URLs de ambiente não podem ser codificadas

Nome do teste: DeploymentTemplate não deve conter Uri codificado

Não codifice URLs de ambiente em seu modelo. Em vez disso, use a função de ambiente para obter dinamicamente essas URLs durante a implantação. Para obter uma lista dos hosts de URL bloqueados, consulte o caso de teste.

No Bicep, use a regra Linter - sem URL de ambiente codificado.

O exemplo a seguir falha porque a URL é codificada.

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

O teste também falha quando usado com concat ou uri.

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

O exemplo a seguir passa.

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

Localização usa parâmetro

Nome do teste: O local não deve ser codificado

Para definir o local de um recurso, seus modelos devem ter um parâmetro nomeado location com o tipo definido como string. No modelo principal, azuredeploy.json 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 location não deve ter um local padrão.

Os usuários de modelo podem ter acesso limitado a regiões onde podem criar recursos. Um local de recurso codificado pode impedir que os usuários criem um recurso. A "[resourceGroup().location]" expressão pode bloquear usuários se o grupo de recursos tiver sido 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 location parâmetro padrão para o local do grupo de recursos, os usuários podem usar o valor padrão quando 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 falha porque o recurso está definido como resourceGroup().locationlocation .

{
  "$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 location parâmetro, mas falha porque o parâmetro assume como padrão um local codificado.

{
  "$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 passa quando o modelo é usado como o modelo principal. Crie um parâmetro que tenha como padrão o local do grupo de recursos, mas permita 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": {}
}

Nota

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

Os recursos devem ter localização

Nome do teste: Os recursos devem ter localização

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

No Bicep, use a regra Linter - sem locais codificados.

O exemplo a seguir falha porque o 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 passa 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 passa porque o location parâmetro 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: O tamanho da VM deve ser um parâmetro

Não codifice o hardwareProfile arquivo vmSize. O teste falha quando o hardwareProfile é omitido ou contém um valor codificado. Forneça um parâmetro para que os usuários do seu modelo possam modificar o tamanho da máquina virtual implantada. Para obter mais informações, consulte Microsoft.Compute virtualMachines.

O exemplo a vmSize seguir falha porque o hardwareProfile do objeto é um valor codificado.

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

O exemplo passa 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 para vmSize para fazer 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 min e max são números

Nome do teste: Min e valor 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 falha.

O exemplo a seguir falha porque minValue e maxValue são strings.

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

O exemplo a seguir falha porque somente minValue é usado.

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

O exemplo a seguir passa 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. Para passar neste ensaio, devem ser preenchidas as seguintes condições:

  • 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 um ou "[deployment().properties.templateLink.uri]" o URL de repositório bruto para seu valor padrão.
  • _artifactsLocationSasToken deve ser um secureString.
  • _artifactsLocationSasToken só pode ter uma cadeia de caracteres vazia para seu valor padrão.
  • _artifactsLocationSasToken não pode ter um valor padrão em um modelo aninhado.

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

Variáveis declaradas devem ser usadas

Nome do teste: As variáveis devem ser referenciadas

Este teste localiza variáveis que não são usadas no modelo ou 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.

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

No Bicep, use a regra de Linter - sem variáveis não utilizadas.

O exemplo a seguir falha porque a variável que usa o copy elemento 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 falha porque a expressão que faz referência a uma variável está faltando o colchete à esquerda ([).

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

O exemplo a seguir passa 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 passa porque a expressão é válida.

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

Variável dinâmica não deve usar concat

Nome do teste: Referências de variáveis dinâmicas 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 passa. A variável é definida dinamicamente durante a currentImage 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 da API

Nome do teste: apiVersions deve ser recente

A versão da API para cada recurso deve usar uma versão recente codificada como uma 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 utilize uma versão de pré-visualização quando estiver disponível uma versão mais recente.

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

Saiba mais sobre o cache do kit de ferramentas.

No Bicep, use a regra Linter - use versões recentes da API.

O exemplo a seguir falha 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 falha 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 passa porque é uma versão recente que não é uma versão de visualização.

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

Usar a versão da API codificada

Nome do teste: Provedores apiVersions não é permitido

A versão da API para um tipo de recurso determina quais propriedades estão disponíveis. Forneça uma versão de API codificada em seu modelo. Não recupere uma versão da API determinada durante a implantação porque você não saberá quais propriedades estão disponíveis.

O exemplo a seguir falha.

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

O exemplo a seguir passa.

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

As propriedades não podem estar vazias

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

Não codifice propriedades para um valor vazio. Os valores vazios incluem cadeias de caracteres, objetos ou matrizes nulos e vazios. Se uma propriedade estiver definida como um valor vazio, remova-a do modelo. Você pode definir uma propriedade como um valor vazio durante a implantação, como por meio de um parâmetro.

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

O exemplo a seguir falha porque há propriedades vazias.

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

O exemplo a seguir passa 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 de recurso

Nome do teste: IDs devem ser derivados de ResourceIDs

Ao especificar uma ID de 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 um ID de recurso.

No Bicep, use a regra Linter - use funções de ID de recurso.

O exemplo a seguir falha.

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

O próximo exemplo passa.

"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 de recursos, não use funções desnecessárias para parâmetros opcionais. Por padrão, a função resourceId usa a assinatura atual e o grupo de recursos. Você não precisa fornecer esses valores.

O exemplo a seguir falha porque você não precisa fornecer a ID da assinatura atual e o nome do grupo de recursos.

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

O próximo exemplo passa.

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

Este teste aplica-se a:

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

depende das melhores práticas

Nome do teste: DependsOn Best Practices

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 um recurso implantado condicionalmente, defina a dependência como faria com qualquer recurso. Quando um recurso condicional não é implantado, o Azure Resource Manager o remove automaticamente das dependências necessárias.

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

No Bicep, use a regra Linter - sem entradas desnecessárias.

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

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

O exemplo a seguir falha porque começa com concat.

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

O exemplo a seguir passa.

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

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

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

Ao definir um modelo aninhado ou vinculado com o tipo de recurso, você pode habilitar a Microsoft.Resources/deployments 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, desative a depuração. Você pode remover o debugSetting objeto ou alterar a detailLevel propriedade para none.

O exemplo a seguir falha.

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

O exemplo a seguir passa.

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

Os nomes de usuário Admin não podem ter valor literal

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 fazer referência ao valor do parâmetro.

No Bicep, use a regra Linter - o nome de usuário admin não deve ser literal.

O exemplo a seguir falha com um valor literal.

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

O exemplo a seguir passa com uma expressão.

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

Usar a imagem de VM mais recente

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

Este teste está desativado, mas a saída mostra que ele passou. A melhor prática é verificar o seu modelo para os seguintes critérios:

Se o seu modelo incluir uma máquina virtual com uma imagem, certifique-se de que está a utilizar a versão mais recente da imagem.

No Bicep, use a regra Linter - use uma imagem de VM estável.

Usar imagens de VM estáveis

Nome do teste: Máquinas virtuais não devem ser visualizadas

As máquinas virtuais não devem usar imagens de visualização. O teste verifica se o storageProfile imageReference não usa uma cadeia de caracteres que contém visualização. E essa visualização não é usada nas imageReference propriedades offer, skuou version.

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

No Bicep, use a regra Linter - use uma imagem de VM estável.

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

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

O exemplo a seguir falha quando a visualização é usada em offer, skuou version.

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

O exemplo a seguir passa.

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

Não use a extensão ManagedIdentity

Nome do teste: ManagedIdentityExtension não deve ser usado

Não aplique a ManagedIdentity extensão 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: As saídas não devem conter segredos

Não inclua nenhum valor na outputs seção que potencialmente exponha 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, para que um usuário mal-intencionado possa encontrar essas informações.

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

O exemplo a seguir falha porque 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 falha porque 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')]"
    }
  }
}

Use protectedSettings para commandToExecute secrets

Nome do teste: CommandToExecute deve usar ProtectedSettings para segredos

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

Não use dados secretos settings no objeto porque ele usa texto não criptografado. Para obter mais informações, consulte Microsoft.Compute virtualMachines/extensions, Windows ou Linux.

No Bicep, use a regra Linter - use protectedSettings para commandToExecute secrets.

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

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

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

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

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

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

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

"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 indica apenas que a versão não está incluída no cache do kit de ferramentas. Usar a versão mais recente de uma API, o que é recomendado, pode gerar o aviso.

Saiba mais sobre o cache do kit de ferramentas.

O exemplo a seguir falha 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 falha 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 passa 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 tipo e nome em funções resourceId

Nome do teste: Os recursos não devem ser ambíguos

Este teste está desativado, mas a saída mostra que ele passou. A melhor prática é verificar o seu modelo para os seguintes critérios:

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

Por exemplo, uma resourceId função é 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, consulte observações 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 do modelo aninhado com escopo para avaliar expressões que contenham parâmetros seguros de funções do tipo secureString ou secureObject lista*, como listKeys.inner expressionEvaluationOptions Se o escopo for usado, as outer 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, consulte Microsoft.Resources deployments and Expression evaluation scope in nested templates.

No Bicep, use a regra Linter - parâmetros seguros na implantação aninhada.

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

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

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

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

Próximos passos