Casos de teste para modelos do ARM

Este artigo descreve os testes que são executados com o toolkit de teste de modelos para modelos de Resource Manager do Azure (modelos do ARM). Fornece exemplos que passam ou falham no teste e incluem o nome de cada teste. Para obter mais informações sobre como executar testes ou como executar um teste específico, veja Parâmetros de teste.

Utilizar o esquema correto

Nome do teste: DeploymentTemplate Schema Is Correct

No seu modelo, tem de especificar um valor de esquema válido.

O exemplo seguinte falha porque o esquema é inválido.

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

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

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

O exemplo seguinte passa com um esquema válido.

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

A propriedade do modelo tem de schema 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

Os parâmetros declarados têm de ser utilizados

Nome do teste: Os parâmetros têm de ser referenciados

Este teste localiza parâmetros que não são utilizados no modelo ou parâmetros que não são utilizados numa expressão válida.

Para reduzir a confusão no seu modelo, elimine todos os parâmetros definidos, mas não utilizados. A eliminação de parâmetros não utilizados simplifica as implementações de modelos porque não tem de fornecer valores desnecessários.

No Bicep, utilize a regra linter – sem parâmetros não utilizados.

O exemplo seguinte falha porque a expressão que referencia um parâmetro não tem o parêntese reto à esquerda ([).

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

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

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

Os parâmetros seguros não podem ter a predefinição hard-coded

Nome do teste: Os Parâmetros de Cadeia de Carateres Seguros Não Podem Ter Predefinição

Não forneça um valor predefinido codificado para um parâmetro seguro no seu modelo. Um parâmetro seguro pode ter uma cadeia vazia como um valor predefinido ou utilizar a função newGuid numa expressão.

Pode utilizar os tipos secureString ou secureObject parâmetros que contêm valores confidenciais, como palavras-passe. Quando um parâmetro utiliza um tipo seguro, o valor do parâmetro não é registado ou armazenado no histórico de implementações. Esta ação impede um utilizador malicioso de detetar o valor sensível.

Quando fornece um valor predefinido, esse valor é detetável por qualquer pessoa que possa aceder ao modelo ou ao histórico de implementações.

No Bicep, utilize a regra linter – predefinição do parâmetro seguro.

O exemplo seguinte falha.

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

O exemplo seguinte passa.

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

O exemplo seguinte passa porque a newGuid função é utilizada.

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

Os URLs do ambiente não podem ser codificados

Nome do teste: DeploymentTemplate Must Not Contain Hardcoded Uri (Nome do teste: DeploymentTemplate Não Pode Conter Uri Codificado)

Não introduza URLs de ambiente de código rígido no seu modelo. Em vez disso, utilize a função de ambiente para obter dinamicamente estes URLs durante a implementação. Para obter uma lista dos anfitriões de URL bloqueados, veja o caso de teste.

No Bicep, utilize a regra linter – sem URL de ambiente codificado.

O exemplo seguinte falha porque o URL está codificado.

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

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

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

O exemplo seguinte passa.

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

A localização utiliza o parâmetro

Nome do teste: Localização Não Deve Ser Codificada

Para definir a localização de um recurso, os modelos devem ter um parâmetro com o nome location com o tipo definido como string. No modelo principal, azuredeploy.json ou mainTemplate.json, este parâmetro pode ser predefinido para a localização do grupo de recursos. Nos modelos ligados ou aninhados, o parâmetro de localização não deve ter uma localização predefinida.

Os utilizadores de modelos podem ter acesso limitado a regiões onde podem criar recursos. Uma localização de recursos codificada pode impedir os utilizadores de criar um recurso. A "[resourceGroup().location]" expressão pode bloquear os utilizadores se o grupo de recursos tiver sido criado numa região à qual o utilizador não consegue aceder. Os utilizadores bloqueados não conseguem utilizar o modelo.

Ao fornecer um location parâmetro predefinido para a localização do grupo de recursos, os utilizadores podem utilizar o valor predefinido quando for conveniente, mas também especificar uma localização diferente.

No Bicep, utilize a regra linter – sem expressões de localização fora dos valores predefinidos dos parâmetros.

O exemplo seguinte falha porque o recurso location 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 exemplo seguinte utiliza um location parâmetro, mas falha porque o parâmetro é predefinido para uma localização codificada.

{
  "$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 seguinte passa quando o modelo é utilizado como o modelo principal. Crie um parâmetro predefinido para a localização do grupo de recursos, mas permite que os utilizadores 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 utilizado como um modelo ligado, o teste falhará. Quando utilizado como um modelo ligado, remova o valor predefinido.

Os recursos devem ter localização

Nome do teste: Recursos Devem Ter Localização

A localização de um recurso deve ser definida como uma expressão de modelo ou global. Normalmente, a expressão de modelo utilizaria o location parâmetro descrito em Localização utiliza o parâmetro .

No Bicep, utilize a regra linter – sem localizações codificadas.

O exemplo seguinte falha 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 seguinte 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 exemplo seguinte também é aprovado porque o location parâmetro utiliza uma expressão. O recurso location utiliza 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 utiliza o parâmetro

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

Não codize o hardwareProfile código rígido do vmSizeobjeto . O teste falha quando o hardwareProfile é omitido ou contém um valor codificado. Forneça um parâmetro para que os utilizadores do seu modelo possam modificar o tamanho da máquina virtual implementada. Para obter mais informações, consulte Microsoft.Compute virtualMachines.

O exemplo seguinte falha porque o hardwareProfile objeto vmSize é um valor hard-coded.

"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 utiliza uma expressão para vmSize referenciar o 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

Quando define um parâmetro com minValue e maxValue, especifique-os como números. Tem de utilizar minValue e maxValue como um par ou o teste falha.

O exemplo seguinte falha porque minValue e maxValue são cadeias de carateres.

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

O exemplo seguinte falha porque só minValue é utilizado.

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

O exemplo seguinte passa porque minValue e maxValue são números.

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

Parâmetro artefactos definido corretamente

Nome do teste: parâmetro artefactos

Quando incluir parâmetros para _artifactsLocation e _artifactsLocationSasToken, utilize as predefinições e os tipos corretos. As seguintes condições têm de ser cumpridas para passar neste teste:

  • Se fornecer um parâmetro, tem de fornecer o outro.
  • _artifactsLocation tem de ser um string.
  • _artifactsLocation tem de ter um valor predefinido no modelo principal.
  • _artifactsLocation não pode ter um valor predefinido num modelo aninhado.
  • _artifactsLocation tem de ter o URL de "[deployment().properties.templateLink.uri]" repositório não processado para o valor predefinido.
  • _artifactsLocationSasToken tem de ser um secureString.
  • _artifactsLocationSasToken só pode ter uma cadeia vazia para o valor predefinido.
  • _artifactsLocationSasToken não pode ter um valor predefinido num modelo aninhado.

No Bicep, utilize a regra linter - parâmetros de artefactos.

As variáveis declaradas têm de ser utilizadas

Nome do teste: As variáveis têm de ser referenciadas

Este teste localiza variáveis que não são utilizadas no modelo ou que não são utilizadas numa expressão válida. Para reduzir a confusão no seu modelo, elimine as variáveis definidas, mas não utilizadas.

As variáveis que utilizam o copy elemento para iterar valores têm de ser referenciadas. Para obter mais informações, veja Iteração variável em modelos arm.

No Bicep, utilize a regra linter - sem variáveis não utilizadas.

O exemplo seguinte falha porque a variável que utiliza 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 seguinte falha porque a expressão que referencia uma variável não tem o parêntese reto à esquerda ([).

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

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

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

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

Nome do teste: Referências de Variáveis Dinâmicas Não Devem Utilizar Concat

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

O exemplo seguinte passa. A currentImage variável é definida dinamicamente durante a implementaçã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')]"
    }
  }
}

Utilizar a versão recente da API

Nome do teste: apiVersions Deve Ser Recente

A versão da API para cada recurso deve utilizar uma versão recente codificada como uma cadeia. O teste avalia a versão da API no seu modelo em relação às versões do fornecedor de recursos na cache do toolkit. 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 não foi encontrada uma versão da API indica apenas que a versão não está incluída na cache do toolkit. A utilização da versão mais recente de uma API, que é recomendada, pode gerar o aviso.

Saiba mais sobre a cache do toolkit.

No Bicep, utilize a regra do Linter - utilize versões de API recentes.

O exemplo seguinte 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 seguinte falha porque é utilizada uma versão de pré-visualização quando está disponível uma versão mais recente.

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

O exemplo seguinte é aprovado porque é uma versão recente que não é uma versão de pré-visualização.

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

Utilizar a versão da API hard-coded

Nome do teste: Fornecedores apiVersions Não É Permitido

A versão da API para um tipo de recurso determina que propriedades estão disponíveis. Forneça uma versão de API hard-coded no seu modelo. Não obtenha uma versão da API determinada durante a implementação porque não saberá quais as propriedades que estão disponíveis.

O exemplo seguinte falha.

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

O exemplo seguinte 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 codumente as propriedades para um valor vazio. Os valores vazios incluem cadeias, objetos ou matrizes nulos e vazios. Se uma propriedade estiver definida para um valor vazio, remova essa propriedade do modelo. Pode definir uma propriedade para um valor vazio durante a implementação, tal como através de um parâmetro.

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

O exemplo seguinte falha porque existem propriedades vazias.

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

O exemplo seguinte 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"
  }
]

Utilizar funções de ID de Recurso

Nome do teste: Os IDs devem ser derivados de ResourceIDs

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

Não utilize a função concat para criar um ID de recurso.

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

O exemplo seguinte falha.

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

O exemplo seguinte passa.

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

A função ResourceId tem os parâmetros corretos

Nome do teste: Os ResourceIds não devem conter

Ao gerar IDs de recursos, não utilize funções desnecessárias para parâmetros opcionais. Por predefinição, a função resourceId utiliza a subscrição atual e o grupo de recursos. Não precisa de fornecer esses valores.

O exemplo seguinte falha porque não precisa de fornecer o ID de subscrição atual e o nome do grupo de recursos.

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

O exemplo seguinte passa.

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

Este teste aplica-se a:

Para reference e list*, o teste falha quando utiliza concat para construir o ID do recurso.

melhores práticas dependsOn

Nome do teste: DependsOn Best Practices

Ao definir as dependências de implementação, não utilize a função if para testar uma condição. Se um recurso depender de um recurso implementado condicionalmente, defina a dependência como faria com qualquer recurso. Quando um recurso condicional não é implementado, o Azure Resource Manager remove-o automaticamente das dependências necessárias.

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

No Bicep, utilize a regra linter – não existem entradas dependsOn desnecessárias.

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

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

O exemplo seguinte falha porque começa com concat.

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

O exemplo seguinte passa.

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

As implementações aninhadas ou ligadas não podem utilizar a depuração

Nome do teste: Os Recursos de Implementação Não Podem Ser Depuração

Quando define um modelo aninhado ou ligado com o Microsoft.Resources/deployments tipo de recurso, pode ativar a depuração. A depuração é utilizada quando precisa de testar um modelo, mas pode expor informações confidenciais. Antes de o modelo ser utilizado na produção, desative a depuração. Pode remover o debugSetting objeto ou alterar a detailLevel propriedade para none.

O exemplo seguinte falha.

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

O exemplo seguinte passa.

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

Administração nomes de utilizador não podem ser um valor literal

Nome do teste: adminUsername Não Deve Ser Literal

Ao definir um adminUserName, não utilize um valor literal. Crie um parâmetro para o nome de utilizador e utilize uma expressão para referenciar o valor do parâmetro.

No Bicep, utilize a regra linter – o nome de utilizador administrador não deve ser literal.

O exemplo seguinte falha com um valor literal.

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

O exemplo seguinte passa com uma expressão.

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

Utilizar a imagem de VM mais recente

Nome do teste: as imagens da VM devem utilizar a versão mais recente

Este teste está desativado, mas o resultado mostra que passou. A melhor prática é verificar o modelo para obter 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, utilize a regra do Linter – utilize uma imagem de VM estável.

Utilizar imagens de VM estáveis

Nome do teste: Máquinas Virtuais Não Deve Ser Pré-visualização

As máquinas virtuais não devem utilizar imagens de pré-visualização. O teste verifica o storageProfile para verificar se o imageReference não utiliza uma cadeia que contém a pré-visualização. E essa pré-visualização não é utilizada 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, utilize a regra do Linter – utilize uma imagem de VM estável.

O exemplo seguinte falha porque imageReference é uma cadeia que contém a pré-visualização.

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

O exemplo seguinte falha quando a pré-visualização é utilizada em offer, skuou version.

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

O exemplo seguinte passa.

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

Não utilizar a extensão ManagedIdentity

Nome do teste: ManagedIdentityExtension não pode ser utilizado

Não aplique a ManagedIdentity extensão a uma máquina virtual. A extensão foi preterida em 2019 e já não deveria ser utilizada.

As saídas não podem incluir segredos

Nome do teste: Saídas Não Podem Conter Segredos

Não inclua quaisquer valores na outputs secção que possam expor segredos. Por exemplo, parâmetros seguros de funções de tipo secureString ou secureObject, ou lista* como listKeys.

O resultado de um modelo é armazenado no histórico de implementações, pelo que um utilizador mal intencionado pode encontrar essas informações.

No Bicep, utilize a regra linter – as saídas não devem conter segredos.

O exemplo seguinte falha porque inclui um parâmetro seguro num 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 seguinte falha porque utiliza 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')]"
    }
  }
}

Utilizar protectedSettings para os segredos commandToExecute

Nome do teste: CommandToExecute Tem de Utilizar ProtectedSettings para segredos

Para recursos com o tipo CustomScript, utilize o encriptado protectedSettings quando commandToExecute incluir dados secretos, como uma palavra-passe. Por exemplo, os dados secretos podem ser utilizados em parâmetros seguros do tipo secureString ou secureObjectfunções de lista* como listKeys, ou scripts personalizados.

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

No Bicep, utilize a regra do Linter – utilize protectedSettings para os segredos commandToExecute.

O exemplo seguinte falha porque settings utiliza commandToExecute com um parâmetro seguro.

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

O exemplo seguinte falha porque settings utiliza commandToExecute com uma listKeys função.

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

O exemplo seguinte é aprovado porque protectedSettings utiliza commandToExecute com um parâmetro seguro.

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

O exemplo seguinte é aprovado porque protectedSettings utiliza commandToExecute com uma listKeys função.

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

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

Nome do teste: apiVersions deve ser recente em funções de referência

A versão da API utilizada numa função de referência tem de ser recente e não uma versão de pré-visualização. O teste avalia a versão da API no seu modelo em relação às versões do fornecedor de recursos na cache do toolkit. 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 não foi encontrada uma versão da API indica apenas que a versão não está incluída na cache do toolkit. A utilização da versão mais recente de uma API, que é recomendada, pode gerar o aviso.

Saiba mais sobre a cache do toolkit.

O exemplo seguinte 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 seguinte falha porque a versão da API é uma versão de pré-visualização.

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

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

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

Utilizar o tipo e o nome nas funções resourceId

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

Este teste está desativado, mas o resultado mostra que passou. A melhor prática é verificar o modelo para obter os seguintes critérios:

Um resourceId tem de incluir um tipo de recurso e um nome de recurso. Este teste localiza todas as funções do resourceId modelo e verifica se o recurso é utilizado 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 não é especificado um grupo de recursos.
  • Se um recurso incluir uma condição e um grupo de recursos não for especificado.
  • Se um recurso relacionado contiver alguns segmentos de nomes, mas não todos. Por exemplo, um recurso subordinado contém mais do que um segmento de nome. Para obter mais informações, veja comentários sobre resourceId.

Utilizar o âmbito interno para parâmetros seguros de implementação aninhada

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

Utilize o objeto do expressionEvaluationOptions modelo aninhado com inner âmbito para avaliar expressões que contenham parâmetros seguros de funções de tipo secureString ou secureObjectlista* , como listKeys. Se o outer âmbito for utilizado, as expressões são avaliadas em texto não encriptado no âmbito do modelo principal. Em seguida, o valor seguro é visível para qualquer pessoa com acesso ao histórico de implementações. O valor predefinido de expressionEvaluationOptions é outer.

Para obter mais informações sobre modelos aninhados, veja Microsoft.Resources deployments and Expression evaluation scope in nested templates (Implementações microsoft.resources e âmbito de avaliação de expressões em modelos aninhados).

No Bicep, utilize a regra do Linter – parâmetros seguros na implementação aninhada.

O exemplo seguinte falha porque expressionEvaluationOptions utiliza outer o âmbito para avaliar parâmetros ou list* funções seguros.

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

O exemplo seguinte é aprovado porque expressionEvaluationOptions utiliza inner o âmbito para avaliar parâmetros ou list* funções seguros.

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

Passos seguintes