Dans l’épisode précédent (https://omiossec.github.io/2019-02-11-ARM-COPY-ARAY/) nous avions abordé comment il était possible d’apporter un peu de dynamisme dans un Template ARM en utilisant Copy pour multiplier les déploiements d’une ressource ou d’une propriété d’une ressource.

Mais la limitation est que cela ne s’applique qu’à une seule ressource. Comment faire si l’un déploiement et fait du plusieurs ressources ou groupes de ressources. Bref comment rendre modulaire et scalable un déploiement.

C’est possible grâce à la ressource Deployments (Microsoft.Resources/deployments). Ce n’est pas une ressource Azure à proprement parler. C’est un moyen d’instruire ARM que l’on souhaite effectuer un déploiement à l’intérieur de son Template.

Ce type de déploiement, Microsoft.Resources/deployments, peut être en ligne (Inline), à l’intérieur même du Template (Linked).

Voici un exemple

"resources": [
        {
            "apiVersion": "2018-05-01",
            "name": "Incremental",
            "type": "Microsoft.Resources/deployments",
            "properties": {
                "mode": "Incremental",
                "template": {
                    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                    "contentVersion": "1.0.0.0",
                    "parameters": {},
                    "variables": {},
                    "resources": [
                        {

Dans ce cas, on utilise la Propriété Template. Elle permet d’insérer un template complet dans le fichier JSON. Les paramètres et les variables du template parents sont disponible dans le template enfant.

Mais la partie la plus intéressante est l’utilisation de la propriété TemplateLink. Elle permet de lier des Templates externes. Cela permet de mieux scaler les déploiements et de les rendre modulaire.

{
            "name": "DeployStorageAccount",
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2018-08-01",
            "properties": {
              "mode": "Incremental",
              "templateLink": {
                "uri": "[variables('storageAccountJsonUri')]",
                "contentVersion": "1.0.0.0"
              },
              "parameters": {

                "storageAccountName": {
                  "value": "[parameters('StorageAccountName')]"
                }
              }
            }
          }

Ainsi il est possible d’avoir plusieurs Templates séparés du Template principal, cela permet de mieux les réutiliser et de travailler à plusieurs et par lots sur les parties de l’infrastructure à mettre en place.

Le point de départ est l’utilisation de TemplateLink, cette propriété est l’URI du template à utiliser suivit de la version à prendre en charge.

Mais contrairement à la version Inline, les paramètres et les variables du Template maitre ne sont pas disponible dans les déploiements enfants. Pour passer des données il faut les passer en paramètre (parameters) la ressource déploiement.

Le schéma de déploiement peut se résumer à :

image-center

Le Template master prend les paramètres utilisateurs et orchestre les déploiements des autres Templates. Ces derniers peuvent être des Templates commun, qui peuvent être partagés entre différents projets. C’est le cas des comptes de Storage et des VNET que l’on trouve dans presque tous les projets, et les Templates propres au projet.

Comment mettre en place un tel process de déploiement ?

Pour le développement, il faut prévoir un fichier azdeploy.json pour le Template maitre et un fichier azdeploy.parameter.json pour les paramètres.

Un dossier neestedtemplates est nécessaire pour l’ensemble des fichiers enfants sur lesquels nous allons travailler.

Mais pour le déploiement cela n’est pas suffisant. L’objet TemplateLink a une propriété URI, chaque Template enfant doit être disponible depuis ce lien en http ou https.

Pour plus de contrôle, il est possible d’indiquer la version du Template voulus dans le Template maitre. Le déploiement n’est alors possible que si la version du Template enfant appelé est la même que celle indiqué dans le maître.

Pour effectuer un déploiement avec ces liens, l’une des options possibles est d’utiliser GitHub pour héberger les templates. Mais dans le monde de l’entreprise cela peut ne pas être accepter. La solution est d’utiliser un container blob dans Azure.

Mais si on utilise un storage blob Azure à la place de Github, c’est pour en sécuriser les accès. En même temps que l’on fournit en paramètre (ou en variable) l’URI vers les templates, il faut aussi construire l’URL avec un token SAS

  "_artifactsLocation": {
        "type": "string",
        "metadata": {
            "description": "The Uri where Neested template are stocked"
        }
    },
    "_artifactsLocationSasToken": {
      "type": "securestring",
      "metadata": {
          "description": "Token for _artifactsLocation"
      },
      "defaultValue": ""
  }

Il est possible de construire l’url

"VMJsonUri":  "[concat(parameters('_artifactsLocation'),'/vm.json',parameters('_artifactsLocationSasToken'))]"

Pour préparer cette configuration

$UtilitiesResourceGroup = "Resource group for Template Storage"
$DefaultAzRegion = "northeurope"
$DeployResourceGroup = "Deployment target Resource Group"
$TemplateStorageAccountName = " Template Storage name"
$AzBlobContainerName = "Template Blob Container Storage Name"

# You should tag this RG 
New-AzResourceGroup -Name $UtilitiesResourceGroup -Location $DefaultAzRegion 

$AzStorage = New-AzStorageAccount -ResourceGroupName $UtilitiesResourceGroup -Name $TemplateStorageAccountName -Type Standard_LRS -Location $DefaultAzRegion -Kind StorageV2

New-AzStorageContainer -Name $AzBlobContainerName -Context $AzStorage.Context -Permission off | out-null 

# We can now upload the linked template

Set-AzStorageBlobContent -Container $AzBlobContainerName -Context $AzStorage.Context -File c:\work\neestedtemplates\vm.json

# And create the SAS Token for the containers

$AzSASToken =  New-AzStorageContainerSASToken -Container $AzBlobContainerName -Context $AzStorage.Context -Permission r -ExpiryTime (Get-Date).AddHours(1.0)

Le fichier parameter peut alors être renseigner

"_artifactsLocation": {
            "value" : "https://o1adosdfjkdfd8t.blob.core.windows.net/projet01"
        },

        "_artifactsLocationSasToken": {
            "value": "?sv=2018-03-28&sr=c&sig=XXXXXXXXXXXE%3D&se=2019-03-06T23%3A05%3A31Z&sp=r"
        }