Przypadki testowe dla szablonów usługi ARM

W tym artykule opisano testy uruchamiane przy użyciu zestawu narzędzi do testowania szablonu dla szablonów usługi Azure Resource Manager (szablony usługi ARM). Zawiera przykłady, które kończą się 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: Schemat DeploymentTemplate jest poprawny

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#",
}

Poniższy przykład wyświetla 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 przekazuje prawidłowy schemat.

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

Zadeklarowane parametry muszą być używane

Nazwa testu: do parametrów należy się odwoływać

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 wdrożenia szablonów, ponieważ nie trzeba podawać niepotrzebnych wartości.

W aplikacji 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 przekazuje wynik , ponieważ wyrażenie jest prawidłowe.

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

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

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

Nie należy podawać zakodowanej wartości domyślnej bezpiecznego parametru w szablonie. Bezpieczny parametr może mieć pusty ciąg jako wartość domyślną lub użyć funkcji newGuid w wyrażeniu.

Używasz typów secureString lub secureObject parametrów zawierających poufne wartości, takich 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 każdego, kto może uzyskać dostęp do szablonu lub historii wdrażania.

W aplikacji Bicep użyj reguły Linter — ustawienie domyślne bezpiecznego parametru.

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

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

Następny przykład zostanie pomyślnie przedstawiony.

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

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

"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

W szablonie nie są zakodowane adresy URL środowiska. 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 przypadek testowy.

W aplikacji Bicep użyj reguły Linter — bez 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 przekazuje.

"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 szablonach połączonych lub zagnieżdżonych 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 blokować 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ż zasób location jest ustawiony na resourceGroup().locationwartość .

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

W następnym przykładzie użyto parametru location , ale nie powiedzie się , ponieważ parametr jest domyślnie ustawiony na lokalizację zakodowaną.

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

Poniższy przykład przekazuje, gdy szablon jest używany jako główny szablon. Utwórz parametr, który domyślnie określa 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": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "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 na wyrażenie szablonu lub global. Wyrażenie szablonu zwykle używa parametru opisanego location w sekcji Location używa parametru.

W aplikacji Bicep użyj reguły Linter — nie ma zakodowanych na stałe lokalizacji.

Poniższy przykład kończy się niepowodzeniem , ponieważ element 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": "2021-02-01",
      "name": "storageaccount1",
      "location": "westus",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

Poniższy przykład przekazuje wartość , ponieważ zasób location jest ustawiony na globalwartość .

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

Następny przykład jest również przekazywanalocation, ponieważ parametr 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": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "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 element zostanie pominięty lub zawiera zakodowaną wartość. 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 zakodowaną wartością.

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

Przykład jest przekazywana , gdy parametr określa wartość dla vmSizeelementu :

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

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

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "2020-12-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 parametru i maxValuenależy określić 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 ciągi są maxValue ciągami.

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

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

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

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

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

Poprawnie zdefiniowany parametr Artifacts

Nazwa testu: parametr artifacts

W przypadku uwzględnienia parametrów dla _artifactsLocation elementów 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ć elementem string.
  • _artifactsLocation musi mieć wartość domyślną w głównym szablonie.
  • _artifactsLocation nie może mieć wartości domyślnej w szablonie zagnieżdżonym.
  • _artifactsLocation musi mieć adres "[deployment().properties.templateLink.uri]" URL pierwotnego repozytorium lub dla jego wartości domyślnej.
  • _artifactsLocationSasToken musi być elementem 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 aplikacji Bicep użyj reguły Linter — parametry artefaktów.

Zadeklarowane zmienne muszą być używane

Nazwa testu: Zmienne muszą się odwoływać

Ten test znajduje 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 zmienne zdefiniowane, ale nie są używane.

Zmienne używające copy elementu do iterowania wartości muszą być przywołyne. Aby uzyskać więcej informacji, zobacz Iteracja zmiennych w szablonach usługi ARM.

W pliku Bicep użyj reguły Linter — nieużywane zmienne.

Poniższy przykład kończy się niepowodzeniem , ponieważ zmienna, która używa copy elementu, nie jest przywołyna.

{
  "$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 nawiasu kwadratowego wiodącego ([).

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

Poniższy przykład przechodzi, ponieważ zmienna jest przywoływalana w pliku 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ć współbieżności

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

Czasami trzeba dynamicznie skonstruować zmienną na podstawie wartości innej zmiennej lub parametru. Nie używaj funkcji concat podczas ustawiania wartości. Zamiast tego użyj obiektu, który zawiera dostępne opcje i dynamicznie pobierz 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 powinna być ostatnio używana

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 szablonie względem wersji dostawcy zasobów w pamięci podręcznej zestawu narzędzi. Wersja interfejsu API, która ma mniej niż dwa lata od daty uruchomienia testu, jest uważana za najnowszą. Nie używaj wersji zapoznawczej, gdy jest dostępna większa wersja.

Ostrzeżenie informujące, że wersja interfejsu API nie została znaleziona tylko wskazuje, że wersja nie jest uwzględniona 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 zestawu narzędzi.

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

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

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2019-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 najnowsza wersja, która nie jest wersją zapoznawcza.

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

Używanie zakodowanej wersji interfejsu API

Nazwa testu: Dostawcy apiVersions nie jest dozwolona

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": "2020-12-01",
    ...
  }
]

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

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

Nie należy kodować właściwości do pustej wartości. Puste wartości to null i puste ciągi, obiekty lub tablice. Jeśli właściwość jest ustawiona na pustą wartość, 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 szablonie zagnieżdżonym może zawierać puste właściwości. Aby uzyskać więcej informacji na temat szablonów zagnieżdżonych, zobacz Wdrożenia Microsoft.Resources.

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

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-01-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": "2021-01-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]",
    "sku": {
      "name": "Standard_LRS",
      "tier": "Standard"
    },
    "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 aplikacji 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'))]"
}

Następny przykład przechodzi.

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

Funkcja ResourceId ma poprawne parametry

Nazwa testu: Identyfikatory zasobów 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 trzeba podać bieżącego identyfikatora subskrypcji i nazwy grupy zasobów.

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

Następny przykład przechodzi.

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

Ten test dotyczy:

W przypadku reference programu i list*test kończy się niepowodzeniem , gdy jest używany concat do konstruowania identyfikatora zasobu.

dependsOn best practices (najlepsze rozwiązania dotyczące zależności)

Nazwa testu: DependsOn Best Practices

Podczas ustawiania zależności wdrożenia 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, usługa Azure Resource Manager automatycznie usunie go z wymaganych zależności.

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

W pliku Bicep użyj reguły Linter — brak 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')]"
]

Wdrożenia zagnieżdżone lub połączone nie mogą używać debugowania

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

Podczas definiowania zagnieżdżonego lub połączonego szablonu z typem Microsoft.Resources/deployments zasobu można włączyć debugowanie. Debugowanie jest używane w przypadku konieczności przetestowania szablonu, ale może uwidaczniać poufne informacje. Przed rozpoczęciem pracy z szablonem 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"
}

Administracja nazwy użytkowników nie mogą być wartością literału

Nazwa testu: adminUsername nie powinien być literałem

W przypadku ustawiania wartości adminUserNameliterału nie należy używać wartości literału. Utwórz parametr nazwy użytkownika i użyj wyrażenia, aby odwołać się do wartości parametru.

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

Poniższy przykład kończy się niepowodzeniem z wartością literału.

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

Poniższy przykład przekazuje wyrażenie.

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

Korzystanie z najnowszego obrazu maszyny wirtualnej

Nazwa testu: Obrazy maszyn wirtualnych powinny używać najnowszej wersji

Ten test jest wyłączony, ale dane wyjściowe pokazują, że zostały przekazane. 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 aplikacji 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 wartość , storageProfile aby sprawdzić, czy imageReference ciąg zawierający podgląd nie jest używany. 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 aplikacji Bicep użyj reguły Linter — użyj stabilnego obrazu maszyny wirtualnej.

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

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

Poniższy przykład kończy się niepowodzeniem , gdy wersja zapoznawcza jest używana w offersystemie , 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 wycofane w 2019 r. i nie powinno już być używane.

Dane wyjściowe nie mogą zawierać wpisów tajnych

Nazwa testu: Dane wyjściowe nie mogą zawierać wpisów tajnych

Nie uwzględniaj żadnych wartości w outputs sekcji, która potencjalnie uwidacznia wpisy tajne. Na przykład bezpieczne parametry typu secureString lub secureObjectlub listy* funkcje, takie jak listKeys.

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

W aplikacji Bicep użyj reguły Linter — dane wyjściowe nie powinny zawierać wpisów tajnych.

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żywanie funkcji protectedSettings dla wpisów tajnych poleceniaToExecute

Nazwa testu: CommandToExecute musi używać wartości ProtectedSettings dla wpisów tajnych

W przypadku zasobów o typie CustomScriptużyj zaszyfrowanego protectedSettings elementu, jeśli commandToExecute zawiera dane tajne, takie jak hasło. Na przykład dane tajne mogą być używane w bezpiecznych parametrach typu secureString lub secureObject, list* funkcji, takich jak listKeys, lub skrypty niestandardowe.

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

W aplikacji Bicep użyj reguły Linter — użyj wartości protectedSettings dla wpisów tajnych poleceniaToExecute.

Poniższy przykład kończy się niepowodzeniem , ponieważ settings jest używany commandToExecute z bezpiecznym parametrem.

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

Poniższy przykład kończy się niepowodzeniemlistKeys, ponieważ settings używa commandToExecute funkcji.

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

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

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

W poniższym przykładzie jest przekazywana funkcja , ponieważ protectedSettings jest używana 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ć najnowsza, a nie wersja zapoznawcza. Test ocenia wersję interfejsu API w szablonie względem wersji dostawcy zasobów w pamięci podręcznej zestawu narzędzi. Wersja interfejsu API, która ma mniej niż dwa lata od daty uruchomienia testu, jest uważana za najnowszą.

Ostrzeżenie informujące, że wersja interfejsu API nie została znaleziona tylko wskazuje, że wersja nie jest uwzględniona 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 zestawu narzędzi.

Poniższy przykład kończy się niepowodzeniem , ponieważ wersja interfejsu API jest większa 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 jest mniejsza niż dwa lata i nie jest wersją zapoznawcza.

"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 zostały przekazane. Najlepszym rozwiązaniem jest sprawdzenie szablonu pod kątem następujących kryteriów:

Identyfikator resourceId 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 prawidłową składnią. W przeciwnym razie funkcja jest uważana za niejednoznaczną.

Na przykład funkcja jest uznawana resourceId 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, a grupa zasobów nie jest określona.
  • 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 resourceId uwagi.

Używanie zakresu wewnętrznego dla zagnieżdżonych parametrów bezpieczeństwa wdrożenia

Nazwa testu: Bezpieczne params we wdrożeniach zagnieżdżonych

Użyj obiektu szablonu expressionEvaluationOptions zagnieżdżonego z zakresem inner , aby ocenić wyrażenia zawierające bezpieczne parametry typu secureString lub secureObjectlisty* funkcji, takich jak listKeys. outer Jeśli zakres jest używany, wyrażenia są oceniane w postaci zwykłego tekstu w zakresie szablonu nadrzędnego. Bezpieczna wartość jest następnie widoczna dla wszystkich osób 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 Microsoft.Resources deployments and Expression evaluation scope in nested templates (Wdrożenia Microsoft.Resources i zakres oceny wyrażeń) w szablonach zagnieżdżonych.

W aplikacji 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": "2021-04-01",
    "name": "nestedTemplate",
    "properties": {
      "expressionEvaluationOptions": {
        "scope": "outer"
      }
    }
  }
]

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

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

Następne kroki