Тестовые случаи для шаблонов ARM
В этой статье описываются тесты, которые выполняются с помощью набора средств тестирования для шаблонов Azure Resource Manager (шаблонов ARM). Здесь приводятся примеры, которые проходят и не проходят эти тесты с указанием имени каждого теста. Дополнительные сведения о выполнении тестов или какого-то определенного теста см. в разделе Параметры тестирования.
Использование правильной схемы
Имя теста: Схема DeploymentTemplate правильная
В шаблоне необходимо указать допустимое значение схемы.
Следующий пример не проходит тест, так как схема является недопустимой.
{
"$schema": "https://schema.management.azure.com/schemas/2019-01-01/deploymentTemplate.json#",
}
Следующий пример отображает предупреждение, так как версия схемы 2015-01-01
является нерекомендуемой и не поддерживается.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
}
Следующий пример проходит тест, используя правильную схему.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
}
Свойству schema
в шаблоне должна быть задана одна из следующих схем:
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
Должны использоваться объявленные параметры
Имя теста: Должны быть указаны объявленные параметры
Этот тест находит параметры, которые не используются в шаблоне или имеют недопустимые выражения.
Чтобы сократить путаницу в шаблоне, удалите все параметры, которые определены, но не используются. Устранение неиспользуемых параметров упрощает развертывания шаблона, избавляя вас от необходимости вводить ненужные значения.
В Bicep используйте правило Linter — неиспользуемые параметры.
Следующий шаблон не проходит тест, так как в выражении со ссылкой на параметр отсутствует открывающая квадратная скобка ([
).
"resources": [
{
"location": " parameters('location')]"
}
]
Следующий пример содержит допустимое выражение и проходит тест.
"resources": [
{
"location": "[parameters('location')]"
}
]
Защищенные параметры не могут иметь прописанные в коде значения по умолчанию
Имя теста: Строковые параметры безопасности не могут иметь значения по умолчанию
Не задавайте жестко запрограммированное значение по умолчанию для параметра безопасности в шаблоне. Защищенный параметр может иметь в качестве значения по умолчанию пустую строку или использовать в выражении функцию newGuid.
Типы secureString
и secureObject
используются для параметров с конфиденциальными значениями, например для паролей. Если параметр использует безопасный тип, значение параметра не заносится в журнал и не сохраняется в журнале развертывания. Это действие не позволит злоумышленнику обнаружить конфиденциальное значение.
Если вы предоставляете значение по умолчанию, оно может быть обнаружено любым пользователем, имеющим доступ к шаблону или журналу развертывания.
В Bicep используйте правило Linter — безопасный параметр по умолчанию.
Следующий пример не проходит тест.
"parameters": {
"adminPassword": {
"defaultValue": "HardcodedPassword",
"type": "secureString"
}
}
Пример ниже проходит тест.
"parameters": {
"adminPassword": {
"type": "secureString"
}
}
Следующий пример проходит тест, так как в нем используется функция newGuid
.
"parameters": {
"secureParameter": {
"type": "secureString",
"defaultValue": "[newGuid()]"
}
}
URL-адреса окружения не могут иметь прописанные в коде значения
Имя теста: DeploymentTemplate не должен содержать жестко заданный URI
Не следует прописывать в коде URL-адреса окружения в шаблоне. Вместо этого используйте функцию environment для динамического получения URL-адресов во время развертывания. Список заблокированных узлов URL-адресов см. в разделе Тестовый случай.
В Bicep используйте правило Linter — url-адрес жестко закодированных сред.
Следующий пример не проходит тест, так как URL-адрес прописан в коде.
"variables":{
"AzureURL":"https://management.azure.com"
}
Тест также завершается ошибкой при использовании concat или uri.
"variables":{
"AzureSchemaURL1": "[concat('https://','gallery.azure.com')]",
"AzureSchemaURL2": "[uri('gallery.azure.com','test')]"
}
Следующий пример проходит тест.
"variables": {
"AzureSchemaURL": "[environment().gallery]"
}
В расположении используется параметр
Имя теста: Расположение не должно быть жестко запрограммировано
Чтобы задать расположение ресурса, в шаблонах нужно указать параметр location
с типом string
. В основном шаблоне (azuredeploy.json или mainTemplate.json) этот параметр может по умолчанию содержать расположение группы ресурсов. В связанных или вложенных шаблонах параметр location не должен содержать расположение по умолчанию.
Пользователи шаблонов могут иметь ограниченный доступ к регионам, в которых они могут создавать ресурсы. Прописанное в коде расположение ресурса может привести к тому, что пользователь не сможет создать ресурс. Выражение "[resourceGroup().location]"
будет блокировать пользователей, если группа ресурсов создана в недоступном для них регионе. Заблокированные пользователи не смогут использовать шаблон.
Если указать параметр location
, в котором по умолчанию задано расположение группы ресурсов, пользователи смогут использовать значение по умолчанию, если это удобно, или указать другое расположение.
В Bicep используйте правило Linter — выражения расположения за пределами значений параметров по умолчанию.
Следующий пример не проходит тест, так как в шаблоне location
имеет значение 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"
}
}
]
}
Следующий пример использует параметр location
, но не проходит тест, так как этот параметр в качестве значения по умолчанию использует прописанное в коде расположение.
{
"$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": {}
}
Следующий пример проходит этот тест, если шаблон используется как основной. Создайте параметр, который в качестве значения по умолчанию использует расположение группы ресурсов, но позволяет пользователям указать другое значение.
{
"$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": {}
}
Примечание.
Если предыдущий пример используется в качестве связанного шаблона, он не пройдет тест. При использовании в качестве связанного шаблона удалите значение по умолчанию.
Ресурсы должны иметь расположение
Имя теста: Ресурсы должны иметь расположение
Для расположения ресурса должно быть задано выражение шаблона или global
. В выражении шаблона обычно используется параметр location
, описанный в разделе В расположении используется параметр.
В Bicep используйте правило Linter — не закодированные расположения.
Следующий пример не проходит тест, так как location
не является выражением или 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": {}
}
Следующий пример проходит тест, так как ресурс location
имеет значение 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": {}
}
Следующий пример также проходит тест, так как параметр location
использует выражение. Ресурс location
использует значение выражения.
{
"$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": {}
}
Размер виртуальной машины должен быть параметром
Имя теста: Размер виртуальной машины должен быть параметром
Не следует прописывать в коде vmSize
для объекта hardwareProfile
. Этот тест завершается ошибкой, если hardwareProfile
пропускается или содержит прописанное в коде значение. Предоставьте параметр, чтобы пользователи шаблона могли изменять размер развернутой виртуальной машины. См. дополнительные сведения о Microsoft.Compute virtualMachines.
Следующий пример не проходит тест, так как у объекта hardwareProfile
параметр vmSize
имеет прописанное в коде значение.
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2020-12-01",
"name": "demoVM",
"location": "[parameters('location')]",
"properties": {
"hardwareProfile": {
"vmSize": "Standard_D2_v3"
}
}
}
]
Этот пример проходит тест, если параметр задает значение для vmSize
:
"parameters": {
"vmSizeParameter": {
"type": "string",
"defaultValue": "Standard_D2_v3",
"metadata": {
"description": "Size for the virtual machine."
}
}
}
Затем hardwareProfile
применяет выражение для vmSize
, что указать ссылку на значение этого параметра.
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2020-12-01",
"name": "demoVM",
"location": "[parameters('location')]",
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSizeParameter')]"
}
}
}
]
Минимальное и максимальное значения являются числами
Имя теста: Минимальное и максимальное значения являются числами
Если вы указываете для параметра minValue
и maxValue
, они должны иметь числовые значения. minValue
и maxValue
всегда используются вместе, иначе тест завершается ошибкой.
Следующий пример не проходит тест, так как minValue
и maxValue
имеют строковые значения.
"exampleParameter": {
"type": "int",
"minValue": "0",
"maxValue": "10"
}
Следующий пример не проходит тест, так как используется только minValue
.
"exampleParameter": {
"type": "int",
"minValue": 0
}
Следующий пример проходит тест, так как minValue
и maxValue
имеют числовые значения.
"exampleParameter": {
"type": "int",
"minValue": 0,
"maxValue": 10
}
Параметр артефактов определен правильно
Имя теста: Параметр артефактов
При включении параметров для _artifactsLocation
и _artifactsLocationSasToken
используйте правильные значения по умолчанию и типы. Для прохождения этого теста должны быть выполнены следующие условия.
- Если вы предоставляете один параметр, необходимо указать и другой.
_artifactsLocation
должен иметь типstring
._artifactsLocation
должен иметь значение по умолчанию в основном шаблоне._artifactsLocation
не может иметь значение по умолчанию во вложенном шаблоне._artifactsLocation
должен иметь значение по умолчанию"[deployment().properties.templateLink.uri]"
или URL-адрес репозитория необработанных данных._artifactsLocationSasToken
должен иметь типsecureString
._artifactsLocationSasToken
может иметь в качестве значения по умолчанию только пустую строку._artifactsLocationSasToken
не может иметь значение по умолчанию во вложенном шаблоне.
В Bicep используйте правило Linter — параметры артефактов.
Необходимо использовать объявленные переменные
Имя теста: Переменные должны быть указаны по ссылке
Этот тест ищет переменные, которые не используются в шаблоне или используются в недопустимом выражении. Чтобы сократить путаницу в шаблоне, удалите все переменные, которые определены, но не используются.
Переменные, которые используют элемент copy
для перебора значений, должны иметь ссылки. Дополнительные сведения см. в статье Итерация переменной в шаблонах ARM.
В Bicep используйте правило Linter — неиспользуемые переменные.
Следующий пример не проходит тест, так как в нем нет ссылок на переменную, которая использует элемент copy
.
{
"$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": {}
}
Следующий шаблон не проходит тест, так как в выражении со ссылкой на переменную отсутствует открывающая квадратная скобка ([
).
"outputs": {
"outputVariable": {
"type": "string",
"value": " variables('varExample')]"
}
}
Следующий пример проходит тест, так как в 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')]"
}
}
}
Следующий пример содержит допустимое выражение и проходит тест.
"outputs": {
"outputVariable": {
"type": "string",
"value": "[variables('varExample')]"
}
}
Динамическая переменная не должна использовать Concat
Имя теста: Ссылки на динамические переменные не должны использовать Concat
Иногда необходимо динамически создать переменную на основе значения другой переменной или параметра. Не используйте функцию concat при задании значения. Вместо этого следует использовать объект, в котором есть доступные параметры, и динамически получать одно из свойств объекта во время развертывания.
Следующий пример проходит тест. Переменная currentImage
задается динамически во время развертывания.
{
"$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')]"
}
}
}
Использование последней версии API
Имя теста: Значением apiVersions должна быть последняя версия
Версия API для каждого ресурса должна указывать свежую версию, прописанную в коде в виде строки. Этот тест сравнивает версию API в приложении с версиями поставщика ресурсов в кэше набора средств. Свежей считается версия API, созданная менее чем за два года до даты выполнения теста. Не используйте предварительную версию, если доступна более свежая.
Предупреждение о том, что версия API не найдена, указывает, что версия не включена в кэш набора инструментов. Предупреждение может возникать, если в соответствии с рекомендациями используется самая свежая версия API.
См. дополнительные сведения о кэше набора средств.
В Bicep используйте правило Linter. Используйте последние версии API.
Следующий пример не проходит тест, так как версия API в нем старше двух лет.
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "storageaccount1",
"location": "[parameters('location')]"
}
]
Следующий пример не проходит тест, так как используется предварительная версия при наличии более свежей.
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2020-08-01-preview",
"name": "storageaccount1",
"location": "[parameters('location')]"
}
]
Следующий пример проходит тест, так как используется свежая версия, которая не является предварительной.
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-02-01",
"name": "storageaccount1",
"location": "[parameters('location')]"
}
]
Использование прописанной в коде версии API
Имя теста: apiVersions поставщиков запрещены
Версия API для типа ресурсов определяет доступные свойства. Укажите в шаблоне жестко запрограммированную версию API. Не извлекайте версию API, которая определяется в процессе развертывания, так как не известно, какие свойства доступны.
Следующий пример не проходит тест.
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "[providers('Microsoft.Compute', 'virtualMachines').apiVersions[0]]",
...
}
]
Следующий пример проходит тест.
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2020-12-01",
...
}
]
Свойства не могут быть пустыми
Имя теста: В шаблоне не должно быть пустых свойств
Не прописывайте в коде для свойств пустое значение. Пустыми являются значения NULL, пустые строки, объекты или массивы. Если свойству присвоено пустое значение, удалите это свойство из шаблона. Но вы можете присвоить свойству пустое значение во время развертывания, например с помощью параметра.
Свойство template
во вложенном шаблоне может содержать пустые свойства. Дополнительные сведения о вложенных шаблонах см. в статье Развертывания Microsoft.Resources.
Следующий пример не проходит тест, так как в нем есть пустые свойства.
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-01-01",
"name": "storageaccount1",
"location": "[parameters('location')]",
"sku": {},
"kind": ""
}
]
Следующий пример проходит тест, так как свойства в нем содержат значения.
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-01-01",
"name": "storageaccount1",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage"
}
]
Использование функций идентификатора ресурса
Имя теста: Идентификаторы должны быть производными от идентификаторов ресурсов
При указании идентификатора ресурса используйте одну из функций идентификатора ресурса. Допустимые функции:
Не используйте функцию concat для создания идентификатора ресурса.
В Bicep используйте правило Linter — используйте функции идентификатора ресурса.
Следующий пример не проходит тест.
"networkSecurityGroup": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]"
}
Пример ниже проходит тест.
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}
Функция ResourceId имеет правильные параметры
Имя теста: Идентификаторы ресурсов не должны содержать
При создании идентификаторов ресурсов не используйте ненужные функции для необязательных параметров. По умолчанию функция resourceId использует текущую подписку и группу ресурсов. Указывать эти значения не нужно.
Следующий пример не проходит тест, так как не нужно указывать идентификатор текущей подписки и имя группы ресурсов.
"networkSecurityGroup": {
"id": "[resourceId(subscription().subscriptionId, resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}
Пример ниже проходит тест.
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}
Этот тест применяется к:
Для reference
и list*
тест завершается ошибкой при использовании concat
для создания идентификатора ресурса.
Рекомендации по dependsOn
Имя теста: Рекомендации по DependsOn
При задании зависимостей развертывания не используйте функцию if для проверки условия. Если один ресурс зависит от ресурса, который развертывается условно, установите зависимость так же, как и для любого другого ресурса. Если условный ресурс не развернут, Azure Resource Manager автоматически удаляет его из числа необходимых зависимостей.
Элемент dependsOn
не может начинаться с функции concat.
В Bicep используйте правило Linter — ненужные записи не зависят от элементов.
Следующий пример не проходит тест, так как содержит функцию if
.
"dependsOn": [
"[if(equals(parameters('newOrExisting'),'new'), variables('storageAccountName'), '')]"
]
Следующий пример не проходит тест, так как начинается с concat
.
"dependsOn": [
"[concat(variables('storageAccountName'))]"
]
Следующий пример проходит тест.
"dependsOn": [
"[variables('storageAccountName')]"
]
Вложенные или связанные развертывания не могут использовать отладку
Имя теста: Ресурсы развертывания не должны быть отладкой
Если вы определяете вложенный или связанный шаблон с типом ресурса Microsoft.Resources/deployments
, для него можно включить отладку. Отладка помогает выполнить тестирование шаблона, если в нем есть конфиденциальная информация. Перед развертыванием шаблона в рабочей среде отключите отладку. Вы можете просто удалить объект debugSetting
или указать для его свойства detailLevel
значение none
.
Следующий пример не проходит тест.
"debugSetting": {
"detailLevel": "requestContent"
}
Следующий пример проходит тест.
"debugSetting": {
"detailLevel": "none"
}
Имя пользователя администратора не может быть литеральным значением
Имя теста: Значение adminUsername не должен быть литералом
Если вы задаете значение adminUserName
, не используйте литеральное значение. Создайте параметр для имени пользователя и укажите выражение со ссылкой на значение этого параметра.
В Bicep используйте правило Linter— имя пользователя администратора не должно быть литеральным.
Следующий пример не проходит тест, так как содержит литеральное значение.
"osProfile": {
"adminUserName": "myAdmin"
}
Следующий пример проходит тест так как используется выражение.
"osProfile": {
"adminUsername": "[parameters('adminUsername')]"
}
Использование последней версии образа виртуальной машины
Имя теста: Должна использоваться последняя версия образа виртуальной машины
Этот тест отключен, но в выходных данных отображается как пройденный. Мы рекомендуем проверить шаблон на соответствие следующим критериям:
Если в шаблоне есть виртуальная машина с образом, она должна использовать последнюю версию образа.
В Bicep используйте правило Linter — используйте стабильный образ виртуальной машины.
Использование стабильных образов виртуальных машин
Имя теста: Нельзя использовать предварительные версии виртуальных машин
Виртуальные машины не должны использовать предварительные образы. Этот тест проверяет в storageProfile
, не использует ли imageReference
строковое значение с подстрокой preview и не используется ли подстрока preview в свойствах imageReference
: offer
, sku
или version
.
Дополнительные сведения о свойстве imageReference
см. в документации по Microsoft.Compute virtualMachines и Microsoft.Compute virtualMachineScaleSets.
В Bicep используйте правило Linter — используйте стабильный образ виртуальной машины.
Следующий пример не проходит тест, так как imageReference
является строкой и содержит preview.
"properties": {
"storageProfile": {
"imageReference": "latest-preview"
}
}
Следующий пример не проходит тест, так как содержит preview в значениях offer
, sku
или version
.
"properties": {
"storageProfile": {
"imageReference": {
"publisher": "Canonical",
"offer": "UbuntuServer_preview",
"sku": "16.04-LTS-preview",
"version": "preview"
}
}
}
Следующий пример проходит тест.
"storageProfile": {
"imageReference": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "16.04-LTS",
"version": "latest"
}
}
Не использовать расширение ManagedIdentity
Имя теста: Нельзя использовать расширение ManagedIdentity
Не применяйте расширение ManagedIdentity
к виртуальной машине. Расширение было признано устаревшим в 2019 г. и больше не должно использоваться.
Выходные данные не могут содержать секреты
Имя теста: Выходные данные не должны содержать секреты
Не включайте в раздел outputs
значения, которые могут предоставлять секреты. Например, защитите все параметры с типом secureString
или secureObject
, а также функции list*, например listKeys
.
Выходные данные шаблона хранятся в журнале развертывания, поэтому злоумышленник может найти эту информацию.
В Bicep используйте правило Linter. Выходные данные не должны содержать секреты.
Следующий пример не проходит тест, так как в его выходных данных содержится защищенный параметр.
{
"$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'))]"
}
}
}
Следующий пример не проходит тест, поскольку в его выходных данных используется функция list*.
{
"$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')]"
}
}
}
Использование protectedSettings для секретов commandToExecute
Имя теста: CommandToExecute должны использовать ProtectedSettings для секретов
Для ресурсов с типом CustomScript
используйте зашифрованное значение protectedSettings
, если commandToExecute
содержит пароли или другие секретные данные. Секретные данные могут содержаться в параметрах с типом secureString
или secureObject
, функциях list* (например, listKeys
) и пользовательских скриптах.
Не используйте секретные данные в объекте settings
, так как он использует открытый текст. Дополнительные сведения см. в разделах документации по Microsoft.Compute virtualMachines/extensions для Windows и Linux.
В Bicep используйте правило Linter — используйте защищенные наборыSettings для секретов commandToExecute.
Следующий пример не проходит тест, так как settings
использует commandToExecute
для защищенного параметра.
"parameters": {
"adminPassword": {
"type": "secureString"
}
}
...
"properties": {
"type": "CustomScript",
"settings": {
"commandToExecute": "[parameters('adminPassword')]"
}
}
Следующий пример не проходит тест, так как settings
использует commandToExecute
с функцией listKeys
.
"properties": {
"type": "CustomScript",
"settings": {
"commandToExecute": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
}
}
Следующий пример проходит тест, так как protectedSettings
использует commandToExecute
для защищенного параметра.
"parameters": {
"adminPassword": {
"type": "secureString"
}
}
...
"properties": {
"type": "CustomScript",
"protectedSettings": {
"commandToExecute": "[parameters('adminPassword')]"
}
}
Следующий пример проходит тест, так как protectedSettings
использует commandToExecute
с функцией listKeys
.
"properties": {
"type": "CustomScript",
"protectedSettings": {
"commandToExecute": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
}
}
Использование свежих версий API в ссылочных функциях
Имя теста: apiVersions Should Be Recent In Reference Functions (В ссылочных функциях должны быть свежие версии API)
Версия API, используемая в ссылочной функции, должна быть свежей и не должна быть предварительной. Этот тест сравнивает версию API в приложении с версиями поставщика ресурсов в кэше набора средств. Свежей считается версия API, созданная менее чем за два года до даты выполнения теста.
Предупреждение о том, что версия API не найдена, указывает, что версия не включена в кэш набора инструментов. Предупреждение может возникать, если в соответствии с рекомендациями используется самая свежая версия API.
См. дополнительные сведения о кэше набора средств.
Следующий пример не проходит тест, так как версия API в нем старше двух лет.
"outputs": {
"stgAcct": {
"type": "string",
"value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01')]"
}
}
Следующий пример не проходит тест, так как используется API предварительной версии.
"outputs": {
"stgAcct": {
"type": "string",
"value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2020-08-01-preview')]"
}
}
Следующий пример проходит тест, так как версия API не старше двух лет и не является предварительной версией.
"outputs": {
"stgAcct": {
"type": "string",
"value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-02-01')]"
}
}
Использование типа и имени в функциях resourceId
Имя теста: Resources Should Not Be Ambiguous (Ресурсы не должны быть неоднозначными)
Этот тест отключен, но в выходных данных отображается как пройденный. Мы рекомендуем проверить шаблон на соответствие следующим критериям:
Значение resourceId должно содержать тип и имя ресурса. Этот тест ищет все функции resourceId
в шаблоне и проверяет, что ресурс в шаблоне используется с правильным синтаксисом. В противном случае функция считается неоднозначной.
Например, функция resourceId
будет неоднозначной в следующих случаях:
- если ресурс не обнаружен в шаблоне и группа ресурсов не указана;
- если ресурс содержит условие и группа ресурсов не указана;
- если связанный ресурс содержит только часть сегментов имени. Например, дочерний ресурс содержит более одного сегмента имени. См. дополнительные сведения в примечаниях о resourceId.
Использование внутренней области действия для защищенных параметров во вложенных развертываниях
Имя теста: Secure Params In Nested Deployments (Защищенные параметры во вложенных развертываниях)
Используйте объект expressionEvaluationOptions
во вложенном шаблоне с областью действия inner
для оценки выражений, которые содержат защищенные параметры с типами secureString
и secureObject
или функции list*, например listKeys
. Если используется область действия outer
, выражения оцениваются в формате обычного текста в области действия родительского шаблона. Защищенный параметр в этом случае становится виден всем, кто имеет доступ к журналу развертывания. Значение expressionEvaluationOptions
по умолчанию — outer
.
Дополнительные сведения о вложенных шаблонах см. в статьях Развертывания Microsoft.Resources и Область вычислений выражения во вложенных шаблонах.
В Bicep используйте правило Linter — безопасные парамы в вложенном развертывании.
Следующий пример не проходит тест, так как expressionEvaluationOptions
использует область действия outer
для оценки защищенных параметров или функций list*
.
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "nestedTemplate",
"properties": {
"expressionEvaluationOptions": {
"scope": "outer"
}
}
}
]
Следующий пример проходит тест, так как expressionEvaluationOptions
использует область действия inner
для оценки защищенных параметров или функций list*
.
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "nestedTemplate",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
}
}
}
]
Следующие шаги
- Дополнительные сведения о запуске набора средств тестирования см. в статье Использование набора средств тестирования ARM.
- Сведения о модуле Microsoft Learn, посвященном использованию набора средств тестирования, см. в разделе Предварительный просмотр изменений и проверка ресурсов Azure с помощью проверок "что, если" и набора средств для тестирования шаблонов ARM.
- Чтобы протестировать файлы параметров, см. статью Тестовые случаи для файлов параметров.
- Дополнительные сведения о тестах createUiDefinition см. в статье Тестовые случаи для createUiDefinition.json.
- Дополнительные сведения о тестах всех файлов см. в статье Тестовые случаи для всех файлов.