Документация
Имеется шаблон для деплоя группы ресурсов — 2
Задача — вынести описание групп безопасности в отдельные шаблоны, что бы подключать их в зависимости от окружения — для Dev свои, для Prod — свои и т.д.
Ресурс Network Security Group для нод выглядит так:
... { "apiVersion": "2015-06-15", "type": "Microsoft.Network/networkSecurityGroups", "name": "[variables('NodesNSGname')]", "location": "[resourceGroup().location]", "tags": { "displayName": "NSG - Remote Access" }, "properties": { "securityRules": [ { "name": "AllowSSHAll", "properties": { "description": "Allow SSH", "protocol": "Tcp", "sourcePortRange": "*", "destinationPortRange": "22", "sourceAddressPrefix": "*", "destinationAddressPrefix": "*", "access": "Allow", "priority": 100, "direction": "Inbound" } } ] } }, ...
Пробуем вложенность.
Создаём отдельный шаблон, например jm-website-nsg-dev.json
, копируем в него ресурс NSG:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { }, "resources": [ { "apiVersion": "2015-06-15", "type": "Microsoft.Network/networkSecurityGroups", "name": "[variables('NodesNSGname')]", "location": "[resourceGroup().location]", "tags": { "displayName": "NSG - Remote Access" }, "properties": { "securityRules": [ { "name": "AllowSSHAll", "properties": { "description": "Allow SSH", "protocol": "Tcp", "sourcePortRange": "*", "destinationPortRange": "22", "sourceAddressPrefix": "*", "destinationAddressPrefix": "*", "access": "Allow", "priority": 100, "direction": "Inbound" } } ] } } ] }
Доступ к шаблонам — только по HTTP/S, поэтому — загружаем его в Storage Account:
Выполняем:
В главном шаблоне на место ресурса NSG вписываем ресурс деплоя:
... { "apiVersion": "2015-01-01", "name": "linkedTemplate", "type": "Microsoft.Resources/deployments", "properties": { "mode": "incremental", "templateLink": { "uri": "https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json", "contentVersion": "1.0.0.0" }, "parameters": { "StorageAccountName":{"value": "[parameters('storageAccountName')]"} } } }, ...
Пробуем:
Странно — ARM при валидации не упал. Значит — в целом схема уже рабочая.
Авторизация.
Переходим в Portal > Storage accounts, генерируем
Выносим его в параметр:
... "parameters": { "SAStoken": { "type": "string", "defaultValue": "?sv=2016-05-31&ss=bfqt&srt=sco&sp=ra&se=2018-03-17T20:31:25Z&st=2017-03-17T12:31:25Z&spr=https&sig=QWy2Sp***%3D" }, ...
Обновляем URI в главном шаблоне:
... "templateLink": { "uri": "[concat('https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json', parameters('SAStoken'))]", "contentVersion": "1.0.0.0" }, ...
Пробуем:
... error: InvalidContentLink : Unable to download deployment content from 'https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json?sv=2016-05-31&ss=bfqt&srt=sco&sp=ra&se=2018-03-17T20:31:25Z&st=2017-03-17T12:31:25Z&spr=https&sig=QWy2***U%3D'. The tracking Id is '6bad400b-6e1e-43cd-98c4-45b324500be5'. Please see https://aka.ms/arm-deploy for usage details. ...
Ну, ок. Ничего удивительного. Сделаем авторизацию позже, а пока — устанавливаем на контейнер права доступа Blob (пубичный доступ на чтение).
Пробуем снова:
Отлично! Уже ругается на параметры — StorageAccountName
, т.к. ресурс деплоя просто скопирован из документации.
В нашем шаблоне NSG мы используем переменную NodesNSGname
:
... "name": "[variables('NodesNSGname')]", ...
В файле шаблона — создаём параметр NodesNSGname
:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "NodesNSGname": { "type": "string" } }, "resources": [ { "apiVersion": "2015-06-15", "type": "Microsoft.Network/networkSecurityGroups", "name": "[parameters('NodesNSGname')]", ...
Обновляем ресурс деплоя в основном шаблоне, передаём во вложенный шаблон переменную NodesNSGname
из главного шаблона:
... "nodesNSGname": "[concat(resourceGroup().name,'-nodes-nsg')]", ...
В ресурсе деплоя указываем:
... "parameters": { "NodesNSGname":{"value": "[variables('NodesNSGname')]"} ...
Полностью он сейчас выглядит так:
... { "apiVersion": "2015-01-01", "name": "linkedTemplate", "type": "Microsoft.Resources/deployments", "properties": { "mode": "incremental", "templateLink": { "uri": "https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json", "contentVersion": "1.0.0.0" }, "parameters": { "NodesNSGname":{"value": "[variables('NodesNSGname')]"} } } }, ...
Обновляем шаблон в Storage account-е:
Пробуем:
Проверяем:
В Portal-е, деплой главного шаблона:
Деплой вложенного шаблона:
Фиксим авторизацию.
Возвращаем права на контейнер — Private.
Пробуем curl
-ом:
Пробуем с токеном:
$ curl "https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json/?sv=2016-05-31&ss=bfqt&srt=sco&sp=rwdlacup&se=2020-03-17T21:18:58Z&st=2017-03-17T13:18:58Z&spr=https,http&sig=QIN***%3D"
Ага, теперь видна ошибка:
Time:2017-03-17T11:23:58.3677617Z</Message><AuthenticationErrorDetail>Signature not valid in the specified time frame: Start [Fri, 17 Mar 2017 13:18:58 GMT] - Expiry [Tue, 17 Mar 2020 21:18:58 GMT] - Current [Fri, 17 Mar 2017 11:23:58 GMT]</AuthenticationErrorDetail></Error>
При деплое через ARM её не видел.
Вчитываемся в неё:
Time:2017-03-17T11:36:37.3456373Z</Message><AuthenticationErrorDetail>Signature not valid in the specified time frame: Start [Fri, 17 Mar 2017 13:33:28 GMT] — Expiry [Fri, 17 Mar 2017 21:33:28 GMT] — Current [Fri, 17 Mar 2017 11:36:37 GMT]</AuthenticationErrorDetail></Error>
Start 13:33:28
Expiry 21:33:28
Current 11:36:37
Current 11:36:37
Временная зона.
Генерируем токен заново, указываем зону UTC +2 (Киев):
Проверяем:
Теперь ошибка 404.
А через ARM — работает.
В основном шаблоне обновляем параметр SAStoken
:
"parameters": { "SAStoken": { "type": "string", "defaultValue": "?sv=2016-05-31&ss=bfqt&srt=sco&sp=rwdlacup&se=2020-03-17T19:37:37Z&st=2017-03-17T11:37:37Z&spr=https&sig=Ilr***k%3D" }, ...
И uri
:
... { "apiVersion": "2015-01-01", "name": "linkedTemplate", "type": "Microsoft.Resources/deployments", "properties": { "mode": "incremental", "templateLink": { "uri": "[concat('https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json', parameters('SAStoken'))]", "contentVersion": "1.0.0.0" ...
Выполняем, проверяем:
С этим разобрались.
Последнее, что хотелось бы слделать — это выбор шаблона в зависимости от того, на какое окружение выполняется развёртывание группы ресурсов.
Проще всего — через добавление нового параметра:
... "environment": { "type": "string", "metadata": { "description": "dev, qa, staging, prod" }, "defaultValue": "dev", "allowedValues": [ "dev", "qa", "staging", "production" ] }, ...
И обновляем uri
:
... "uri": "[concat('https://utils.blob.core.windows.net/templates/jm-website-nsg-', parameters('environment'), '.json', parameters('SAStoken'))]", ...
Проверяем:
Готово.