Partager via


Cas de test pour les modèles ARM

Cet article décrit les tests exécutés avec le kit de ressources de test de modèle pour les modèles ARM (Azure Resource Manager). Il fournit des exemples avec des tests qui réussissent ou qui échouent et inclut le nom de chaque test. Pour plus d’informations sur l’exécution de tests ou sur l’exécution d’un test spécifique, consultez Paramètres de test.

Utiliser le schéma correct

Nom du test : Le schéma DeploymentTemplate est correct

Dans votre modèle, vous devez spécifier une valeur de schéma valide.

Dans l’exemple suivant, le test échoue, car le schéma n’est pas valide.

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

L’exemple suivant affiche un avertissement, car la version de schéma 2015-01-01 est dépréciée et n’est plus gérée.

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

Dans l’exemple suivant, le test réussit car il utilise un schéma valide.

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

La propriété schema du modèle doit être définie sur l’un des schémas suivants :

  • 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

Les paramètres déclarés doivent être utilisés

Nom du test : Les paramètres doivent être référencés

Ce test recherche les paramètres qui ne sont pas utilisés dans le modèle ou qui ne sont pas utilisés dans une expression valide.

Pour améliorer la lisibilité de votre modèle, supprimez tous les paramètres qui sont définis mais qui ne sont pas utilisés. L’élimination des paramètres inutilisés simplifie les déploiements de modèle, car vous n’avez pas besoin de fournir des valeurs qui ne sont pas nécessaires.

Dans Bicep, utilisez Règle de linter – aucun paramètre inutilisé.

Dans l’exemple suivant, le test échoue, car l’expression qui référence un paramètre ne contient pas le crochet ouvrant ([).

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

Dans l’exemple suivant, le test réussit, car l’expression est valide.

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

Les paramètres sécurisés ne peuvent pas avoir de valeur par défaut codée en dur

Nom du test : Les paramètres de chaîne sécurisée ne peuvent pas avoir de valeur par défaut

Ne fournissez pas de valeur par défaut codée en dur pour un paramètre sécurisé dans votre modèle. Un paramètre sécurisé peut avoir une chaîne vide comme valeur par défaut ou utiliser la fonction newGuid dans une expression.

Vous utilisez les types secureString ou secureObject sur les paramètres qui contiennent des valeurs sensibles comme des mots de passe. Lorsqu’un paramètre utilise un type sécurisé, sa valeur n’est pas enregistrée ou stockée dans l’historique de déploiement. Cette action empêche un utilisateur malveillant de découvrir la valeur sensible.

Quand vous fournissez une valeur par défaut, cette valeur peut être découverte par toute personne ayant accès au modèle ou à l’historique de déploiement.

Dans Bicep, utilisez Règle de linter – Valeur par défaut de paramètre sécurisé.

Dans l’exemple suivant, le test échoue.

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

Dans l’exemple suivant, le test réussit.

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

Dans l’exemple suivant, le test réussit, car la fonction newGuid est utilisée.

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

Les URL d’environnement ne peuvent pas être codées en dur

Nom du test : DeploymentTemplate ne doit pas contenir d’URI codé en dur

Ne codez pas en dur les URL d’environnement dans votre modèle. Au lieu de cela, utilisez la fonction environment pour obtenir dynamiquement ces URL pendant le déploiement. Pour obtenir la liste des hôtes d’URL bloqués, consultez le cas de test.

Dans Bicep, utilisez Règle de linter – aucune URL d’environnement codée en dur.

Dans l’exemple suivant, le test échoue, car l’URL est codée en dur.

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

De même, le test échoue quand il est utilisé avec concat ou uri.

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

Dans l’exemple suivant, le test réussit.

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

L’emplacement utilise le paramètre

Nom du test : L’emplacement ne doit pas être codé en dur

Pour la définition de l’emplacement d’une ressource, vos modèles doivent avoir un paramètre nommé location avec le type défini sur string. Dans le modèle principal, azuredeploy.json ou mainTemplate.json, ce paramètre peut correspondre par défaut à l’emplacement du groupe de ressources. Dans les modèles liés ou imbriqués, le paramètre d'emplacement ne doit pas comporter d'emplacement par défaut.

Les utilisateurs de modèle peuvent avoir un accès limité aux régions où ils peuvent créer des ressources. Un emplacement de ressource codé en dur peut empêcher les utilisateurs de créer une ressource. L’expression "[resourceGroup().location]" peut bloquer les utilisateurs si le groupe de ressources a été créé dans une région à laquelle l’utilisateur ne peut pas accéder. Les utilisateurs bloqués ne peuvent pas utiliser le modèle.

En fournissant un paramètre location qui correspond par défaut à l’emplacement du groupe de ressources, les utilisateurs peuvent utiliser la valeur par défaut quand cela leur convient, mais aussi spécifier un autre emplacement.

Dans Bicep, utilisez Règle de linter – aucune expression d’emplacement en dehors des valeurs par défaut des paramètres.

Dans l’exemple suivant, le test échoue, car le paramètre location de la ressource est défini sur 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"
      }
    }
  ]
}

Le prochain exemple utilise un paramètre location, mais le test échoue, car le paramètre est défini par défaut sur un emplacement codé en dur.

{
  "$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": {}
}

Dans l’exemple suivant, le test réussit quand le modèle est utilisé comme modèle principal. Créez un paramètre qui a pour valeur par défaut l’emplacement du groupe de ressources, mais qui permet aux utilisateurs de fournir une valeur différente.

{
  "$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": {}
}

Notes

Si l’exemple précédent est utilisé comme modèle lié, le test échoue. Lorsqu'il est utilisé comme modèle lié, supprimez la valeur par défaut.

Les ressources doivent avoir un emplacement

Nom du test : Les ressources doivent avoir un emplacement

L’emplacement d’une ressource doit être défini sur une expression de modèle ou global. L’expression de modèle utilise généralement le paramètre location décrit dans la section L’emplacement utilise le paramètre.

Dans Bicep, utilisez Règle de linter – Règle de linter – aucun emplacement codé en dur.

Dans l’exemple suivant, le test échoue, car le paramètre location n’est pas une expression 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": {}
}

Dans l’exemple suivant, le test réussit, car le paramètre location de la ressource est défini sur 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": {}
}

Dans l’exemple suivant, le test réussit également, car le paramètre location utilise une expression. Le paramètre location de la ressource utilise la valeur de l’expression.

{
  "$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": {}
}

La taille de machine virtuelle utilise un paramètre

Nom du test : La taille de la machine virtuelle doit être un paramètre

Ne codez pas en dur le paramètre vmSize de l’objet hardwareProfile. Le test échoue quand l’objet hardwareProfile est omis ou contient une valeur codée en dur. Fournissez un paramètre afin que les utilisateurs de votre modèle puissent modifier la taille de la machine virtuelle déployée. Pour plus d’informations, consultez Microsoft.Compute virtualMachines.

Dans l’exemple suivant, le test échoue, car le paramètre vmSize de l’objet hardwareProfile est codé en dur.

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

Dans cet exemple, le test réussit quand un paramètre spécifie une valeur pour vmSize :

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

Ensuite, hardwareProfile utilise une expression pour que vmSize référence la valeur du paramètre :

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

Les valeurs Min et Max sont des nombres

Nom du test : Les valeurs Min et Max sont des nombres

Quand vous définissez un paramètre avec minValue et maxValue, spécifiez ces valeurs comme nombres. Vous devez utiliser minValue et maxValue comme paire, sans quoi le test échoue.

Dans l’exemple suivant, le test échoue, car minValue et maxValue sont des chaînes.

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

Dans l’exemple suivant, le test échoue, car seul minValue est utilisé.

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

Dans l’exemple suivant, le test réussit, car minValue et maxValue sont des nombres.

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

Paramètre des artefacts défini correctement

Nom du test : paramètre artifacts

Lorsque vous incluez des paramètres pour _artifactsLocation et _artifactsLocationSasToken, utilisez les valeurs par défaut et les types appropriés. Les conditions suivantes doivent être satisfaites pour réussir ce test :

  • Si vous fournissez un paramètre, vous devez fournir l’autre.
  • _artifactsLocation doit être de type string.
  • _artifactsLocation doit posséder une valeur par défaut dans le modèle principal.
  • _artifactsLocation ne peut pas posséder une valeur par défaut dans un modèle imbriqué.
  • Par défaut, _artifactsLocation doit être définie sur "[deployment().properties.templateLink.uri]" ou sur l’URL de référentiel brute.
  • _artifactsLocationSasToken doit être de type secureString.
  • _artifactsLocationSasToken ne peut avoir qu’une chaîne vide comme valeur par défaut.
  • _artifactsLocationSasToken ne peut pas posséder une valeur par défaut dans un modèle imbriqué.

Dans Bicep, utilisez Règle de linter – Paramètres d’artefacts.

Les variables déclarées doivent être utilisées

Nom du test : Les variables doivent être référencées

Ce test recherche des variables qui ne sont pas utilisées dans le modèle ou dans une expression valide. Pour améliorer la lisibilité de votre modèle, supprimez toutes les variables qui sont définies mais qui ne sont pas utilisées.

Les variables qui utilisent l’élément copy pour itérer des valeurs doivent être référencées. Pour plus d’informations, consultez Itération de variable dans les modèles ARM.

Dans Bicep, utilisez Règle de linter – aucune variable inutilisée.

Dans l’exemple suivant, le test échoue, car la variable qui utilise l’élément copy n’est pas référencée.

{
  "$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": {}
}

Dans l’exemple suivant, le test échoue, car l’expression qui référence une variable ne contient pas le crochet ouvrant ([).

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

Dans l’exemple suivant, le test réussit, car la variable est référencée dans 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')]"
    }
  }
}

Dans l’exemple suivant, le test réussit, car l’expression est valide.

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

La variable dynamique ne doit pas utiliser concat

Nom du test : Les références de variables dynamiques ne doivent pas utiliser concat

Parfois, vous devez construire dynamiquement une variable basée sur la valeur d’une autre variable ou d’un autre paramètre. N’utilisez pas la fonction concat lors de la définition de la valeur. Au lieu de cela, utilisez un objet qui comprend les options disponibles et récupérez dynamiquement l’une des propriétés de l’objet au cours du déploiement.

Dans l’exemple suivant, le test réussit. La variable currentImage est définie de manière dynamique au cours du déploiement.

{
  "$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')]"
    }
  }
}

Utiliser la version récente de l’API

Nom du test : apiVersions doit être récent

La version d’API de chaque ressource doit correspondre à une version récente, codée en dur comme chaîne. Le test évalue la version d’API dans votre modèle par rapport aux versions du fournisseur de ressources dans le cache du kit de ressources. Une version d’API datant de moins de deux ans par rapport à la date d’exécution du test est considérée comme récente. N’utilisez pas de préversion quand une version plus récente est disponible.

Un avertissement signalant qu’une version d’API n’a pas été trouvée indique uniquement que la version n’est pas incluse dans le cache du kit de ressources. L’utilisation de la version la plus récente d’une API (ce qui est recommandé) peut générer l’avertissement.

Apprenez-en davantage sur le cache du kit de ressources.

Dans Bicep, utilisez Règle de linter – utiliser les versions récentes de l’API.

Dans l’exemple suivant, le test échoue, car la version d’API date de plus de deux ans.

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

Dans l’exemple suivant, le test échoue, car une préversion est utilisée alors qu’une version plus récente est disponible.

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

Dans l’exemple suivant, le test réussit, car il s’agit d’une version récente qui n’est pas une préversion.

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

Utilisez une version d’API codée en dur

Nom du test : Providers apiVersions n’est pas autorisé

La version d’API d’un type de ressource détermine les propriétés disponibles. Fournissez une version d’API codée en dur dans votre modèle. Ne récupérez pas une version d’API déterminée durant le déploiement, car vous ne saurez pas quelles propriétés sont disponibles.

Dans l’exemple suivant, le test échoue.

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

Dans l’exemple suivant, le test réussit.

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

Les propriétés ne peuvent pas être vides

Nom du test : Le modèle ne doit pas contenir d’espaces vides

Ne codez pas en dur les propriétés avec une valeur vide. Les valeurs vides incluent des chaînes, des objets ou des tableaux null et vides. Si une propriété est définie sur une valeur vide, supprimez-la de votre modèle. Vous pouvez définir une propriété sur une valeur vide pendant le déploiement, par exemple par le biais d’un paramètre.

La propriété template dans un modèle imbriqué peut inclure des propriétés vides. Pour plus d’informations sur les modèles imbriqués, consultez déploiements Microsoft.Resources.

Dans l’exemple suivant, le test échoue, car des propriétés sont vides.

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

Dans l’exemple suivant, le test réussit, car les propriétés incluent des valeurs.

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

Utiliser les fonctions ID de ressource

Nom du test : Les ID doivent être dérivés de ResourceID

Lorsque vous spécifiez un ID de ressource, utilisez l’une des fonctions d’ID de ressource. Les fonctions autorisées sont les suivantes :

N’utilisez pas la fonction concat pour créer un ID de ressource.

Dans Bicep, utilisez Règle de linter – utiliser les fonctions ID de la ressource.

Dans l’exemple suivant, le test échoue.

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

Dans l’exemple suivant, le test réussit.

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

La fonction ResourceId possède des paramètres corrects

Nom du test : ResourceIds ne doit pas contenir

Lors de la génération d’ID de ressource, n’utilisez pas de fonctions inutiles pour les paramètres facultatifs. Par défaut, la fonction resourceId utilise le groupe actuel d’abonnements et de ressources. Vous n’avez pas besoin de fournir ces valeurs.

Dans l’exemple suivant, le test échoue, car vous n’avez pas besoin de fournir l’ID d’abonnement et le nom de groupe de ressources actuels.

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

Dans l’exemple suivant, le test réussit.

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

Ce test s’applique à :

Concernant reference et list*, le test échoue quand vous utilisez concat pour construire l’ID de ressource.

Bonnes pratiques pour dependsOn

Nom du test : Bonnes pratiques pour dependsOn

Lors de la définition des dépendances de déploiement, n’utilisez pas la fonction if pour tester une condition. Si une ressource dépend d’une ressource qui est déployée de manière conditionnelle, définissez la dépendance comme vous le feriez avec n’importe quelle ressource. Quand une ressource conditionnelle n’est pas déployée, Azure Resource Manager la supprime automatiquement des dépendances nécessaires.

L’élément dependsOn ne peut pas commencer par une fonction concat.

Dans Bicep, utilisez Règle de linter – aucune entrée dependsOn inutile.

Dans l’exemple suivant, le test échoue, car il contient une fonction if.

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

Dans l’exemple suivant, le test échoue, car il commence par concat.

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

Dans l’exemple suivant, le test réussit.

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

Les déploiements imbriqués ou liés ne peuvent pas utiliser debug

Nom du test : Les ressources de déploiement ne doivent pas être en mode débogage

Quand vous définissez un modèle imbriqué ou lié avec le type de ressource Microsoft.Resources/deployments, vous pouvez activer le débogage. Le débogage est utilisé quand vous devez tester un modèle, mais que vous pouvez exposer des informations sensibles. Avant d’utiliser le modèle en production, désactivez le débogage. Vous pouvez supprimer l’objet debugSetting ou définir la propriété detailLevel sur none.

Dans l’exemple suivant, le test échoue.

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

Dans l’exemple suivant, le test réussit.

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

Les noms d’utilisateur admin ne peuvent pas être des valeurs littérales

Nom du test : adminUsername ne doit pas être un littéral

Quand vous définissez un adminUserName, n’utilisez pas de valeur littérale. Créez un paramètre pour le nom d’utilisateur et utilisez une expression pour référencer la valeur du paramètre.

Dans Bicep, utilisez Règle de linter – le nom d’utilisateur administrateur ne doit pas être un littéral.

Dans l’exemple suivant, le test échoue avec une valeur littérale.

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

Dans l’exemple suivant, le test réussit avec une expression.

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

Utiliser la dernière image de machine virtuelle

Nom du test : Les images de machine virtuelle doivent utiliser la dernière version

Ce test est désactivé, mais la sortie indique qu’il a réussi. Une bonne pratique consiste à vérifier les critères suivants dans votre modèle :

Si votre modèle contient une machine virtuelle avec une image, assurez-vous qu’elle utilise la version la plus récente de l’image.

Dans Bicep, utilisez Règle de linter – utiliser une image de machine virtuelle stable.

Utiliser des images de machine virtuelle stables

Nom du test : Les machines virtuelles ne doivent pas être une préversion

Les machines virtuelles ne doivent pas utiliser d’images de préversion. Le test contrôle storageProfile pour vérifier que imageReference n’utilise pas une chaîne qui contient preview. et que preview n’est pas utilisé dans les propriétés offer, sku ou version de imageReference.

Pour plus d’informations sur la propriété imageReference, consultez Microsoft.Compute virtualMachines et Microsoft.Compute virtualMachineScaleSets.

Dans Bicep, utilisez Règle de linter – utiliser une image de machine virtuelle stable.

Dans l’exemple suivant, le test échoue, car imageReference est une chaîne contenant preview.

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

Dans l’exemple suivant, le test échoue quand preview est utilisé dans offer, sku ou version.

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

Dans l’exemple suivant, le test réussit.

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

Ne pas utiliser l’extension ManagedIdentity

Nom du test : ManagedIdentityExtension ne doit pas être utilisée

N’appliquez pas l’extension ManagedIdentity à une machine virtuelle. Déconseillée depuis 2019, l'extension ne doit plus être utilisée.

Les sorties ne peuvent pas comprendre de secrets

Nom du test : Les sorties ne doivent pas contenir de secrets

N’incluez pas de valeurs dans la section outputs, qui expose potentiellement des secrets. Par exemple, des paramètres sécurisés de type secureString ou secureObject ou des fonctions list* comme listKeys.

La sortie d’un modèle est stockée dans l’historique de déploiement ; aussi un utilisateur malveillant peut-il y trouver ces informations.

Dans Bicep, utilisez Règle de linter – les sorties ne doivent pas contenir de secrets.

Dans l’exemple suivant, le test échoue, car il comprend un paramètre sécurisé dans une valeur de sortie.

{
  "$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'))]"
    }
  }
}

L’exemple suivant échoue, car il utilise une fonction list* dans les sorties.

{
  "$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')]"
    }
  }
}

Utiliser protectedSettings pour les secrets commandToExecute

Nom du test : CommandToExecute doit utiliser ProtectedSettings pour les secrets

Pour les ressources de type CustomScript, utilisez la propriété protectedSettings chiffrée quand commandToExecute inclut des données secrètes comme un mot de passe. Par exemple, les données secrètes peuvent être utilisées dans des paramètres sécurisés de type secureString ou secureObject, des fonctions list* comme listKeys ou des scripts personnalisés.

N’utilisez pas de données secrètes dans l’objet settings, car il utilise du texte clair. Pour plus d’informations, consultez Microsoft.Compute virtualMachines/extensions, Windows ou Linux.

Dans Bicep, utilisez Règle de linter – utiliser protectedSettings pour les secrets commandToExecute.

Dans l’exemple suivant, le test échoue, car settings utilise commandToExecute avec un paramètre sécurisé.

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

Dans l’exemple suivant, le test échoue, car settings utilise commandToExecute avec une fonction listKeys.

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

Dans l’exemple suivant, le test réussit, car protectedSettings utilise commandToExecute avec un paramètre sécurisé.

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

Dans l’exemple suivant, le test réussit, car protectedSettings utilise commandToExecute avec une fonction listKeys.

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

Utilisez des versions d’API récentes dans les fonctions reference

Nom du test : apiVersions Should Be Recent In Reference Functions (Les versions d’API doivent être récentes dans les fonctions reference)

La version d’API utilisée dans une fonction reference doit être récente et ne doit pas être une préversion. Le test évalue la version d’API dans votre modèle par rapport aux versions du fournisseur de ressources dans le cache du kit de ressources. Une version d’API datant de moins de deux ans par rapport à la date d’exécution du test est considérée comme récente.

Un avertissement signalant qu’une version d’API n’a pas été trouvée indique uniquement que la version n’est pas incluse dans le cache du kit de ressources. L’utilisation de la version la plus récente d’une API (ce qui est recommandé) peut générer l’avertissement.

Apprenez-en davantage sur le cache du kit de ressources.

Dans l’exemple suivant, le test échoue, car la version d’API date de plus de deux ans.

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

Dans l’exemple suivant, le test échoue, car la version d’API est une préversion.

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

Dans l’exemple suivant, le test réussit, car la version d’API date de moins de deux ans et n’est pas une préversion.

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

Utilisez un type et un nom dans les fonctions resourceId

Nom du test : Resources Should Not Be Ambiguous (Les ressources ne doivent pas être ambiguës)

Ce test est désactivé, mais la sortie indique qu’il a réussi. Une bonne pratique consiste à vérifier les critères suivants dans votre modèle :

Une fonction resourceId doit inclure un type de ressource et un nom de ressource. Ce test recherche toutes les fonctions resourceId du modèle et vérifie que la ressource est utilisée dans le modèle avec la syntaxe correcte. Dans le cas contraire, la fonction est considérée comme ambiguë.

Par exemple, une fonction resourceId est considérée comme ambiguë :

  • Quand une ressource est introuvable dans le modèle et qu’aucun groupe de ressources n’est spécifié.
  • Si une ressource contient une condition et qu’aucun groupe de ressources n’est spécifié.
  • Si une ressource associée contient certains segments de nom, mais pas tous. Par exemple, une ressource enfant contient plusieurs segments de noms. Pour plus d’informations, consultez les notes sur resourceId.

Utilisez l’étendue inner pour les paramètres sécurisés de déploiements imbriqués

Nom du test :Secure Params In Nested Deployments (Paramètres sécurisés dans des déploiements imbriqués)

Utilisez l’objet expressionEvaluationOptions du modèle imbriqué avec l’étendue inner pour évaluer les expressions qui contiennent des paramètres sécurisés de type secureString ou secureObject ou des fonctions list* comme listKeys. Si l’étendue outer est utilisée, les expressions sont évaluées en texte clair dans l’étendue du modèle parent. La valeur sécurisée est ensuite visible par toute personne ayant accès à l’historique de déploiement. La valeur par défaut de expressionEvaluationOptions est outer.

Pour plus d’informations sur les modèles imbriqués, consultez Déploiements Microsoft.Resources et Étendue de l’évaluation d’expressions dans les modèles imbriqués.

Dans Bicep, utilisez Règle de linter – sécuriser les paramètres dans le déploiement imbriqué.

L’exemple suivant échoue, car expressionEvaluationOptions utilise l’étendue outer pour évaluer des paramètres sécurisés ou des fonctions list*.

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

L’exemple suivant réussit, car expressionEvaluationOptions utilise l’étendue inner pour évaluer des paramètres sécurisés ou des fonctions list*.

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

Étapes suivantes