Udostępnij za pośrednictwem


Przypadki testowe dla szablonów ARM

W tym artykule opisano testy uruchamiane przy użyciu zestawu narzędzi do testowania szablonu dla szablonów Azure Resource Manager (szablony usługi ARM). Zawiera przykłady z powodzeniem lub niepowodzeniem testu i zawierają nazwę każdego testu. Aby uzyskać więcej informacji na temat uruchamiania testów lub uruchamiania określonego testu, zobacz Parametry testu.

Użyj poprawnego schematu

Nazwa testu: DeploymentTemplate ma poprawny schemat

W szablonie należy określić prawidłową wartość schematu.

Poniższy przykład kończy się niepowodzeniem , ponieważ schemat jest nieprawidłowy.

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

W poniższym przykładzie jest wyświetlane ostrzeżenie, ponieważ wersja 2015-01-01 schematu jest przestarzała i nie jest obsługiwana.

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

Poniższy przykład przechodzi walidację przy użyciu prawidłowego schematu.

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

Właściwość szablonu schema musi być ustawiona na jeden z następujących schematów:

  • 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

Parametry zadeklarowane muszą być używane

Nazwa testu: parametry muszą być przywołyne

Ten test znajduje parametry, które nie są używane w szablonie lub parametrach, które nie są używane w prawidłowym wyrażeniu.

Aby zmniejszyć zamieszanie w szablonie, usuń wszystkie zdefiniowane parametry, ale nie są używane. Wyeliminowanie nieużywanych parametrów upraszcza wdrażanie szablonów, ponieważ nie trzeba dostarczać niepotrzebnych wartości.

W Bicep użyj reguły Linter — brak nieużywanych parametrów.

Poniższy przykład kończy się niepowodzeniem , ponieważ w wyrażeniu odwołującym się do parametru brakuje wiodącego nawiasu kwadratowego ([).

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

Poniższy przykład przechodzi, ponieważ wyrażenie jest prawidłowe.

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

Bezpieczne parametry nie mogą mieć zakodowanej na sztywno wartości domyślnej

Nazwa testu: Parametry bezpiecznego ciągu nie mogą mieć wartości domyślnej

Nie udostępniaj zakodowanej wartości domyślnej bezpiecznego parametru w szablonie. Bezpieczny parametr może mieć pusty ciąg jako wartość domyślną lub użyć nowej funkcjiGuid w wyrażeniu.

Można używać typów secureString lub secureObject parametrów zawierających poufne wartości, takie jak hasła. Gdy parametr używa bezpiecznego typu, wartość parametru nie jest rejestrowana ani przechowywana w historii wdrożenia. Ta akcja uniemożliwia złośliwemu użytkownikowi odnajdywanie poufnej wartości.

Po podaniu wartości domyślnej ta wartość jest wykrywalna przez wszystkich, którzy mogą uzyskać dostęp do szablonu lub historii wdrażania.

W Bicep użyj reguły Linter — wartość domyślna bezpiecznego parametru.

Poniższy przykład kończy się niepowodzeniem.

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

W następnym przykładzie przejdziemy dalej.

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

Poniższy przykład przechodzi, ponieważ newGuid funkcja jest używana.

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

Adresy URL środowiska nie mogą być zakodowane w kodzie

Nazwa testu: DeploymentTemplate nie może zawierać zakodowanego na stałe identyfikatora URI

Nie umieszczaj na stałe adresów URL środowiskowych w szablonie. Zamiast tego użyj funkcji środowiska , aby dynamicznie pobierać te adresy URL podczas wdrażania. Aby uzyskać listę zablokowanych hostów adresów URL, zobacz test case.

W Bicep użyj reguły Linter — brak zakodowanego na stałe adresu URL środowiska.

Poniższy przykład kończy się niepowodzeniem , ponieważ adres URL jest zakodowany w kodzie.

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

Test również kończy się niepowodzeniem w przypadku użycia z concat lub uri.

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

Poniższy przykład przechodzi.

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

Lokalizacja używa parametru

Nazwa testu: lokalizacja nie powinna być zakodowana na stałe

Aby ustawić lokalizację zasobu, szablony powinny mieć parametr o nazwie location z typem ustawionym na string. W szablonie głównym azuredeploy.json lub mainTemplate.json ten parametr może być domyślnie ustawiony na lokalizację grupy zasobów. W połączonych lub zagnieżdżonych szablonach parametr lokalizacji nie powinien mieć lokalizacji domyślnej.

Użytkownicy szablonów mogą mieć ograniczony dostęp do regionów, w których mogą tworzyć zasoby. Zakodowana lokalizacja zasobu może uniemożliwić użytkownikom tworzenie zasobu. Wyrażenie "[resourceGroup().location]" może blokować użytkowników, jeśli grupa zasobów została utworzona w regionie, do którego użytkownik nie może uzyskać dostępu. Użytkownicy, którzy są zablokowani, nie mogą używać szablonu.

location Podając parametr domyślny lokalizacji grupy zasobów, użytkownicy mogą używać wartości domyślnej, gdy jest to wygodne, ale także określa inną lokalizację.

W Bicep użyj reguły Linter — brak wyrażeń lokalizacji poza wartościami domyślnymi parametrów.

Poniższy przykład kończy się niepowodzeniem , ponieważ location zasobu jest ustawiony na 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": "2025-06-01",
      "name": "storageaccount1",
      "location": "[resourceGroup().location]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
      }
    }
  ]
}

W następnym przykładzie użyto parametru location, ale nie działa, ponieważ parametr domyślnie wskazuje na twardo zakodowaną lokalizację.

{
  "$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": "2025-06-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
      }
    }
  ],
  "outputs": {}
}

Poniższy przykład działa poprawnie gdy szablon jest używany jako szablon główny. Utwórz parametr, który jest domyślnie ustawiony na lokalizację grupy zasobów, ale umożliwia użytkownikom podanie innej wartości.

{
  "$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": "2025-06-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
      }
    }
  ],
  "outputs": {}
}

Uwaga

Jeśli powyższy przykład jest używany jako połączony szablon, test zakończy się niepowodzeniem. W przypadku użycia jako szablonu połączonego usuń wartość domyślną.

Zasoby powinny mieć lokalizację

Nazwa testu: Zasoby powinny mieć lokalizację

Lokalizacja zasobu powinna być ustawiona jako wyrażenie szablonu lub global. Wyrażenie szablonu zwykle używa parametru location, opisanego w sekcji Lokalizacja używa parametru.

W Bicep użyj reguły Linter — brak zakodowanych lokalizacji.

Poniższy przykład zawodzi, ponieważ location nie jest wyrażeniem ani 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": "2025-06-01",
      "name": "storageaccount1",
      "location": "westus",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
      }
    }
  ],
  "outputs": {}
}

Poniższy przykład przechodzi, ponieważ zasób location jest ustawiony na 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": "2025-06-01",
      "name": "storageaccount1",
      "location": "global",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
      }
    }
  ],
  "outputs": {}
}

Następny przykład również przechodzi, ponieważ parametr location używa wyrażenia. Zasób location używa wartości wyrażenia.

{
  "$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": "2025-06-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
      }
    }
  ],
  "outputs": {}
}

Rozmiar maszyny wirtualnej używa parametru

Nazwa testu: Rozmiar maszyny wirtualnej powinien być parametrem

Nie koduj hardwareProfile trwale obiektu vmSize. Test kończy się niepowodzeniem, gdy hardwareProfile jest pominięte lub zawiera wartość zakodowaną na stałe. Podaj parametr, aby użytkownicy szablonu mogli modyfikować rozmiar wdrożonej maszyny wirtualnej. Aby uzyskać więcej informacji, zobacz Microsoft.Compute virtualMachines.

Poniższy przykład kończy się niepowodzeniem , ponieważ hardwareProfile obiekt vmSize jest wartością zakodowaną na sztywno.

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

Przykład jest przekazywana, gdy parametr określa wartość parametru :vmSize

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

Następnie hardwareProfile używa wyrażenia vmSize, aby odwołać się do wartości parametru:

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

Wartości minimalne i maksymalne to liczby

Nazwa testu: minimalna i maksymalna wartość to liczby

Podczas definiowania parametru za pomocą minValue i maxValue, określ je jako liczby. Musisz użyć parametru minValue i maxValue jako pary lub test zakończy się niepowodzeniem.

Poniższy przykład kończy się niepowodzeniem, ponieważ minValue i maxValue są ciągami.

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

Poniższy przykład kończy się niepowodzeniem , ponieważ jest używany tylko minValue .

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

Poniższy przykład przechodzi, ponieważ minValue i maxValue są liczbami.

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

Parametr Artifacts poprawnie zdefiniowany

Nazwa testu: parametr artefaktów

W przypadku uwzględnienia parametrów dla _artifactsLocation i _artifactsLocationSasTokenużyj poprawnych wartości domyślnych i typów. Aby przejść ten test, należy spełnić następujące warunki:

  • Jeśli podasz jeden parametr, musisz podać drugi.
  • _artifactsLocation musi być string.
  • _artifactsLocation musi mieć wartość domyślną w głównym szablonie.
  • _artifactsLocation nie może mieć wartości domyślnej w zagnieżdżonym szablonie.
  • _artifactsLocation musi mieć jako wartość domyślną albo "[deployment().properties.templateLink.uri]", albo adres URL pierwotnego repozytorium.
  • _artifactsLocationSasToken musi być secureString.
  • _artifactsLocationSasToken Może mieć tylko pusty ciąg dla jego wartości domyślnej.
  • _artifactsLocationSasToken nie może mieć wartości domyślnej w szablonie zagnieżdżonym.

W Bicep użyj reguły Linter — parametry artefaktów.

Zadeklarowane zmienne muszą być używane

Nazwa testu: Zmienne muszą być przywołyne

Ten test wyszukuje zmienne, które nie są używane w szablonie lub nie są używane w prawidłowym wyrażeniu. Aby zmniejszyć zamieszanie w szablonie, usuń wszystkie zdefiniowane zmienne, ale nie są używane.

Do zmiennych używających copy elementu do iterowania wartości należy odwoływać się. Aby uzyskać więcej informacji, zobacz sekcję Iteracja zmiennych w szablonach ARM.

W Bicep użyj reguły Linter — bez nieużywanych zmiennych.

Poniższy przykład kończy się niepowodzeniem , ponieważ zmienna używająca copy elementu nie jest przywołyowana.

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

Poniższy przykład kończy się niepowodzeniem , ponieważ w wyrażeniu odwołującym się do zmiennej brakuje wiodącego nawiasu kwadratowego ([).

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

Poniższy przykład przechodzi, ponieważ zmienna jest odwoływana w 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')]"
    }
  }
}

Poniższy przykład przechodzi, ponieważ wyrażenie jest prawidłowe.

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

Zmienna dynamiczna nie powinna używać concat

Nazwa testu: Odwołania do zmiennych dynamicznych nie powinny używać concat

Czasami trzeba dynamicznie konstruować zmienną na podstawie wartości innej zmiennej lub parametru. Nie używaj funkcji concat podczas ustawiania wartości. Zamiast tego należy użyć obiektu zawierającego dostępne opcje i dynamicznie uzyskać jedną z właściwości z obiektu podczas wdrażania.

Poniższy przykład przechodzi. Zmienna currentImage jest dynamicznie ustawiana podczas wdrażania.

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

Korzystanie z najnowszej wersji interfejsu API

Nazwa testu: apiVersions powinny być aktualne

Wersja interfejsu API dla każdego zasobu powinna używać najnowszej wersji, która jest zakodowana jako ciąg. Test ocenia wersję interfejsu API w twoim szablonie w porównaniu do wersji oferowanych przez dostawcę zasobów zapisanych w pamięci podręcznej zestawu narzędzi. Wersja interfejsu API, która ma mniej niż dwa lata od daty uruchomienia testu, jest uznawana za niedawną. Nie używaj wersji zapoznawczej, gdy jest dostępna najnowsza wersja.

Ostrzeżenie, że nie znaleziono wersji interfejsu API tylko wskazuje, że wersja nie jest zawarta w pamięci podręcznej zestawu narzędzi. Użycie najnowszej wersji interfejsu API, która jest zalecana, może wygenerować ostrzeżenie.

Dowiedz się więcej o pamięci podręcznej toolkit.

W Bicep użyj reguły Linter — użyj ostatnich wersji interfejsu API.

Poniższy przykład kończy się niepowodzeniem , ponieważ wersja interfejsu API ma więcej niż dwa lata.

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

Poniższy przykład kończy się niepowodzeniem , ponieważ wersja zapoznawcza jest używana, gdy jest dostępna nowsza wersja.

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

Poniższy przykład przechodzi, ponieważ jest to niedawna wersja, która nie jest wersją zapoznawczą.

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

Używanie zakodowanej wersji interfejsu API

Nazwa testu: apiVersions dostawców nie są dozwolone

Wersja interfejsu API dla typu zasobu określa, które właściwości są dostępne. Podaj zakodowaną wersję interfejsu API w szablonie. Nie pobieraj wersji interfejsu API określonej podczas wdrażania, ponieważ nie wiesz, które właściwości są dostępne.

Poniższy przykład kończy się niepowodzeniem.

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

Poniższy przykład przechodzi.

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

Właściwości nie mogą być puste

Nazwa testu: szablon nie powinien zawierać wartości pustych

Nie należy kodować właściwości na wartość pustą. Puste wartości obejmują ciągi o wartości null, obiekty lub tablice. Jeśli właściwość jest ustawiona na wartość pustą, usuń właściwość z szablonu. Właściwość można ustawić na wartość pustą podczas wdrażania, na przykład za pomocą parametru.

Właściwość template w zagnieżdżonym szablonie może zawierać puste właściwości. Aby uzyskać więcej informacji na temat szablonów zagnieżdżonych, zobacz wdrożenia zasobów Microsoft.

Poniższy przykład kończy się niepowodzeniem , ponieważ istnieją puste właściwości.

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

Poniższy przykład przechodzi, ponieważ właściwości zawierają wartości.

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

Korzystanie z funkcji identyfikatora zasobu

Nazwa testu: identyfikatory powinny pochodzić z identyfikatorów zasobów

Podczas określania identyfikatora zasobu użyj jednej z funkcji identyfikatora zasobu. Dozwolone funkcje to:

Nie używaj funkcji concat do utworzenia identyfikatora zasobu.

W Bicep użyj reguły Linter — użyj funkcji identyfikatora zasobu.

Poniższy przykład kończy się niepowodzeniem.

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

W następnym przykładzie przejdziemy dalej.

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

Funkcja ResourceId ma poprawne parametry

Nazwa testu: ResourceIds nie powinny zawierać

Podczas generowania identyfikatorów zasobów nie używaj niepotrzebnych funkcji dla parametrów opcjonalnych. Domyślnie funkcja resourceId używa bieżącej subskrypcji i grupy zasobów. Nie musisz podawać tych wartości.

Poniższy przykład kończy się niepowodzeniem , ponieważ nie musisz podawać bieżącego identyfikatora subskrypcji i nazwy grupy zasobów.

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

W następnym przykładzie przejdziemy dalej.

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

Ten test dotyczy:

Dla reference i list* test kończy się niepowodzeniem, gdy wykorzystujesz concat do konstrukcji identyfikatora zasobu.

dependsOn najlepsze rozwiązania

Nazwa testu: DependsOn Best Practices

Podczas ustawiania zależności wdrażania nie należy używać funkcji if do testowania warunku. Jeśli jeden zasób zależy od zasobu, który jest wdrażany warunkowo, ustaw zależność tak, jak w przypadku dowolnego zasobu. Gdy zasób warunkowy nie zostanie wdrożony, Azure Resource Manager automatycznie usunie go z wymaganych zależności.

Element dependsOn nie może zaczynać się od funkcji concat .

W Bicep użyj zasady Lintera — bez niepotrzebnych wpisów dependsOn.

Poniższy przykład kończy się niepowodzeniemif, ponieważ zawiera funkcję.

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

Poniższy przykład kończy się niepowodzeniem , ponieważ rozpoczyna się od concat.

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

Poniższy przykład przechodzi.

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

Zagnieżdżone lub połączone wdrożenia nie mogą używać debugowania

Nazwa testu: Zasoby wdrażania nie mogą być debugowane

Podczas definiowania szablonu zagnieżdżonego lub połączonego z typem zasobu Microsoft.Resources/deployments, można włączyć debugowanie. Debugowanie jest używane, gdy trzeba przetestować szablon, ale może uwidaczniać poufne informacje. Przed zastosowaniem szablonu w środowisku produkcyjnym wyłącz debugowanie. Możesz usunąć debugSetting obiekt lub zmienić detailLevel właściwość na none.

Poniższy przykład kończy się niepowodzeniem.

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

Poniższy przykład przechodzi.

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

Nazwy użytkowników administratora nie mogą być wartością dosłowną

Nazwa testu: adminUsername nie powinien być literałem

Podczas ustawiania adminUserName nie używaj wartości dosłownej. Utwórz parametr nazwy użytkownika i użyj wyrażenia, aby odwołać się do wartości parametru.

W Bicep użyj reguły Linter — nazwa użytkownika administratora nie powinna być dosłowna.

Poniższy przykład nie działa przy wartości literału.

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

Poniższy przykład przechodzi z wyrażeniem.

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

Korzystanie z najnowszego obrazu maszyny wirtualnej

Nazwa testu: Obrazy VM powinny używać najnowszej wersji

Ten test jest wyłączony, ale dane wyjściowe pokazują, że przeszedł pomyślnie. Najlepszym rozwiązaniem jest sprawdzenie szablonu pod kątem następujących kryteriów:

Jeśli szablon zawiera maszynę wirtualną z obrazem, upewnij się, że używa najnowszej wersji obrazu.

W Bicep użyj reguły Linter — użyj stabilnego obrazu maszyny wirtualnej.

Używanie stabilnych obrazów maszyn wirtualnych

Nazwa testu: Virtual Machines nie powinien być w wersji zapoznawczej

Maszyny wirtualne nie powinny używać obrazów w wersji zapoznawczej. Test sprawdza storageProfile, aby zweryfikować, czy imageReference nie używa ciągu zawierającego podgląd. Ta wersja zapoznawcza nie jest używana we imageReference właściwościach offer, skulub version.

Aby uzyskać więcej informacji na temat imageReference właściwości, zobacz Microsoft.Compute virtualMachines i Microsoft.Compute virtualMachineScaleSets.

W Bicep użyj reguły Linter — użyj stabilnego obrazu maszyny wirtualnej.

Poniższy przykład kończy się niepowodzeniem , ponieważ imageReference jest to ciąg zawierający podgląd.

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

Poniższy przykład kończy się niepowodzeniem , gdy wersja zapoznawcza jest używana w systemie offer, skulub version.

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

Poniższy przykład przechodzi.

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

Nie używaj rozszerzenia ManagedIdentity

Nazwa testu: ManagedIdentityExtension nie może być używany

Nie stosuj ManagedIdentity rozszerzenia do maszyny wirtualnej. Rozszerzenie zostało uznane za przestarzałe w 2019 r. i nie powinno już być używane.

Wyniki nie mogą zawierać tajemnic

Nazwa testu: dane wyjściowe nie mogą zawierać sekretów

Nie dołączaj żadnych wartości w outputs sekcji, która potencjalnie uwidacznia wpisy tajne. Na przykład bezpieczne parametry typu secureString lub secureObject, lub funkcje list* takie jak listKeys.

Dane wyjściowe z szablonu są przechowywane w historii wdrażania, więc złośliwy użytkownik może znaleźć te informacje.

W Bicep użyj reguły Linter — wyjścia nie powinny zawierać sekretów.

Poniższy przykład kończy się niepowodzeniem , ponieważ zawiera bezpieczny parametr w wartości wyjściowej.

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

Poniższy przykład kończy się niepowodzeniem, ponieważ używa funkcji list* w danych wyjściowych.

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

Użyj protectedSettings dla tajnych commandToExecute

Nazwa testu: CommandToExecute musi używać ustawień chronionych dla tajnych danych

W przypadku zasobów z typem CustomScriptużyj zaszyfrowanego elementu protectedSettings , jeśli commandToExecute zawierają dane tajne, takie jak hasło. Na przykład dane tajne mogą być używane w bezpiecznych parametrach typu secureString lub secureObject, funkcjach takich jak list* lub własnych skryptach listKeys.

Nie używaj danych tajnych w obiekcie settings, ponieważ używa on tekstu w postaci jawnej. Aby uzyskać więcej informacji, zobacz Microsoft.Compute virtualMachines/extensions, Windows lub Linux.

W Bicep użyj reguły Linter — użyj protectedSettings dla tajnych informacji commandToExecute.

Poniższy przykład kończy się niepowodzeniem z powodu settings użycia commandToExecute z bezpiecznym parametrem.

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

Poniższy przykład nie działa, ponieważ settings używa commandToExecute z funkcją listKeys.

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

Poniższy przykład przechodzi, ponieważ protectedSettings używa commandToExecute z bezpiecznym parametrem.

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

Poniższy przykład przechodzi, ponieważ protectedSettings używa commandToExecute z funkcją listKeys.

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

Używanie najnowszych wersji interfejsu API w funkcjach referencyjnych

Nazwa testu: apiVersions powinna być ostatnio używana w funkcjach referencyjnych

Wersja interfejsu API używana w funkcji referencyjnej musi być aktualna, a nie wersją wstępną. Test ocenia wersję interfejsu API w twoim szablonie w porównaniu do wersji oferowanych przez dostawcę zasobów zapisanych w pamięci podręcznej zestawu narzędzi. Wersja interfejsu API, która ma mniej niż dwa lata od daty uruchomienia testu, jest uznawana za niedawną.

Ostrzeżenie, że nie znaleziono wersji interfejsu API tylko wskazuje, że wersja nie jest zawarta w pamięci podręcznej zestawu narzędzi. Użycie najnowszej wersji interfejsu API, która jest zalecana, może wygenerować ostrzeżenie.

Dowiedz się więcej o pamięci podręcznej toolkit.

Poniższy przykład kończy się niepowodzeniem , ponieważ wersja interfejsu API ma więcej niż dwa lata.

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

Poniższy przykład kończy się niepowodzeniem , ponieważ wersja interfejsu API jest wersją zapoznawcza.

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

Poniższy przykład przechodzi, ponieważ wersja interfejsu API nie ma jeszcze dwóch lat i nie jest wersją zapoznawczą.

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

Używanie typu i nazwy w funkcjach resourceId

Nazwa testu: Zasoby nie powinny być niejednoznaczne

Ten test jest wyłączony, ale dane wyjściowe pokazują, że przeszedł pomyślnie. Najlepszym rozwiązaniem jest sprawdzenie szablonu pod kątem następujących kryteriów:

Identyfikator zasobu musi zawierać typ zasobu i nazwę zasobu. Ten test wyszukuje wszystkie funkcje szablonu resourceId i sprawdza, czy zasób jest używany w szablonie z poprawną składnią. W przeciwnym razie funkcja jest uważana za niejednoznaczną.

Na przykład resourceId funkcja jest uważana za niejednoznaczną:

  • Jeśli zasób nie zostanie znaleziony w szablonie, a grupa zasobów nie zostanie określona.
  • Jeśli zasób zawiera warunek i nie określono grupy zasobów.
  • Jeśli powiązany zasób zawiera niektóre, ale nie wszystkie segmenty nazw. Na przykład zasób podrzędny zawiera więcej niż jeden segment nazw. Aby uzyskać więcej informacji, zobacz Uwagi dotyczące resourceId.

Użyj zakresu wewnętrznego dla bezpiecznych parametrów zagnieżdżonego wdrożenia

Nazwa testu: Bezpieczne parametry zagnieżdżonych wdrożeń

Użyj obiektu zagnieżdżonego szablonu z zakresem inner, aby ocenić wyrażenia zawierające bezpieczne parametry typu secureString lub secureObject bądź funkcje typu list*, takie jak listKeys. Jeśli zakres outer jest używany, wyrażenia są oceniane jako zwykły tekst w zakresie szablonu nadrzędnego. Bezpieczna wartość jest następnie widoczna dla każdej osoby z dostępem do historii wdrożenia. Wartość domyślna expressionEvaluationOptions to outer.

Aby uzyskać więcej informacji na temat szablonów zagnieżdżonych, zobacz Wdrożenia Microsoft.Resources i Zakres oceny wyrażeń w zagnieżdżonych szablonach.

W Bicep użyj reguły Linter — bezpieczne parametry w zagnieżdżonym wdrożeniu.

Poniższy przykład kończy się niepowodzeniem , ponieważ expressionEvaluationOptions używa outer zakresu do oceny bezpiecznych parametrów lub list* funkcji.

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

Poniższy przykład przechodzi test, ponieważ expressionEvaluationOptions używa inner zakresu do oceny bezpieczeństwa parametrów lub list* funkcji.

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

Następne kroki