DevOps Elastic Hayway
Document

SUBSCRIBE TO GET FULL ACCESS TO THE E-BOOKS FOR FREE 🎁SUBSCRIBE NOW

Professional Dropdown with Icon

SUBSCRIBE NOW TO GET FREE ACCESS TO EBOOKS

Azure DevOpsLesson 23 / 3113 min readUpdated September 13, 2026

Templates ARM Azure : structure, paramètres et déploiement

À la fin de ce tutoriel, vous saurez lire l’anatomie d’un template ARM JSON, écrire des paramètres et un fichier de paramètres (sans secrets), déployer un lab Storage LRS cheap en canadacentral avec az deployment group what-if / create, brancher la tâche AzureResourceManagerTemplateDeployment@3, comparer Bicep et situer ARM/Bicep face à Terraform.

Niveau : Débutant → intermédiaire · Temps estimé : 60–80 min · Versions testées : Azure CLI 2.60+, API Storage 2023-05-01, région canadacentral · Dernière vérification : 2026-09-11

Slug proposé : azure-arm-templates · Série : Azure / DevOps (IaC) · Région lab Azure : canadacentral

Prérequis

  • Azure Monitor & Application Insights (contexte série)
  • Abonnement lab + Contributor (créer rg-ado-lab-arm)
  • Azure CLI (az version) ; extension VS Code ARM Tools recommandée
  • MFA ; lab cheap ; suppression en fin de session
  • Bases JSON

Coût estimé : Storage Standard_LRS = quelques centimes. Pas d’App Service Plan payant (B1+ à l’heure) — note optionnelle plus bas. Pas de VM ni Premium GRS.

Ce que nous allons construire

Repo ado-lab
  └── infra/
        ├── main.json                 (ARM — Storage LRS lab)
        ├── main.parameters.json      (non-secrets uniquement)
        └── main.bicep               (équivalent pédagogique)
Azure (canadacentral)
  └── rg-ado-lab-arm
        └── stadolabXXXXX            (préfixe court + uniqueString)
CLI / Pipeline
  └── az deployment group what-if|create
  └── AzureResourceManagerTemplateDeployment@3

(Schéma à remplacer par une image locale Excalidraw / draw.io, alt : « Déploiement ARM : resource group canadacentral, Storage Account lab low-cost, what-if puis create ».)

Fond EN conservé et enrichi : lab renommé, coût maîtrisé, quiz, erreurs, scénario terrain.

Étape 1 — Comment fonctionne un déploiement ARM

Toute ressource Azure passe par Azure Resource Manager. Un template ARM est un JSON déclaratif : ARM valide, calcule les dépendances et crée / met à jour (souvent en parallèle).

  • Scopes : resource group (lab), subscription, management group, tenant.
  • Idempotence : redéployer un template inchangé ne change rien.
  • Modes : Incremental (défaut) ; Complete (supprime l’absent du template — prudence).
  • what-if ≈ terraform plan : diff Create / Modify / Delete / NoChange avant d’agir.

Étape 2 — Anatomie d’un template ARM JSON

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": { },
  "variables":  { },
  "functions":  [ ],
  "resources":  [ ],
  "outputs":    { }
}
Section Rôle
parameters Valeurs fournies au déploiement (région, SKU, préfixe). Types, defaultValue, allowedValues, minLength, secureString
variables Valeurs dérivées (noms uniques, tags) pour éviter la répétition
functions Fonctions utilisateur (rares en lab)
resources Ressources : type, apiVersion, name, location, properties, dependsOn optionnel
outputs Valeurs renvoyées (noms, IDs) — jamais de clés / connection strings dans un tutoriel public

Les expressions vivent entre crochets : [parameters('x')], [uniqueString(resourceGroup().id)], [resourceId(...)].

Étape 3 — Resource group canadacentral et lab Storage cheap

az group create -n rg-ado-lab-arm -l canadacentral

Noms Storage : globalement uniques, 3–24 caractères, minuscules et chiffres. Stratégie lab : préfixe court + uniqueString(resourceGroup().id).

Fichier infra/main.json — Storage LRS, HTTPS only, TLS 1.2, pas d’accès blob public, pas de secret en output :

{
  "$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": "Région lab — canadacentral via le RG" }
    },
    "storagePrefix": {
      "type": "string",
      "defaultValue": "stadolab",
      "minLength": 3,
      "maxLength": 11,
      "metadata": { "description": "Préfixe court pour nom de storage" }
    },
    "storageSku": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "allowedValues": [ "Standard_LRS", "Standard_GRS" ],
      "metadata": { "description": "SKU Storage — LRS = cheap lab" }
    }
  },
  "variables": {
    "storageName": "[toLower(concat(parameters('storagePrefix'), uniqueString(resourceGroup().id)))]",
    "tags": {
      "environment": "lab",
      "managedBy": "arm-template",
      "series": "ado-lab-arm"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2023-05-01",
      "name": "[variables('storageName')]",
      "location": "[parameters('location')]",
      "tags": "[variables('tags')]",
      "sku": { "name": "[parameters('storageSku')]" },
      "kind": "StorageV2",
      "properties": {
        "minimumTlsVersion": "TLS1_2",
        "allowBlobPublicAccess": false,
        "supportsHttpsTrafficOnly": true
      }
    }
  ],
  "outputs": {
    "storageAccountName": {
      "type": "string",
      "value": "[variables('storageName')]"
    },
    "storageAccountId": {
      "type": "string",
      "value": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]"
    }
  }
}

Points pédagogiques : (1) location hérite du RG → canadacentral ; (2) uniqueString stabilise le suffixe tant que le RG existe ; (3) zéro listKeys / SAS en output.

Expressions ARM utiles en lab

Les crochets [...] évaluent des fonctions au déploiement : parameters, variables, resourceGroup().location / .id, uniqueString, concat / format / toLower, resourceId, reference. dependsOn ordonne quand il n’y a pas de référence explicite ; avec resourceId (ou Bicep), la dépendance est souvent implicite.

Évitez les dépendances circulaires : ARM refuse le template. Séparez les ressources ou déployez en deux passes plutôt que A↔B.

Note optionnelle — App Service (coûteux)

L’exemple EN ajoute parfois App Service Plan + Web App (dependsOn, identité managée). Un plan B1+ facture dès la création : restez sur Storage LRS ici. Essai Free/F1 seulement si budgété, puis az group delete. Jamais de connection string en appSettings commités.

Pour illustrer dependsOn / identité managée avec Plan + Web App : Free/F1 seulement si disponible, validez, puis az group delete. Ne laissez jamais un B1/P1v3 oublié. Au quotidien, restez sur le lab Storage.

Étape 4 — Parameter files et références Key Vault (sans secrets)

infra/main.parameters.json — non-secrets uniquement :

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storagePrefix": { "value": "stadolab" },
    "storageSku": { "value": "Standard_LRS" }
  }
}

Attention : le $schema doit être deploymentParameters, pas celui du template.

Pour un secret (ex. MDP DB), référence Key Vault — ARM résout au déploiement, sans valeur en clair :

"dbPassword": {
  "reference": {
    "keyVault": {
      "id": "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>"
    },
    "secretName": "db-password"
  }
}

L’identité de déploiement (SP / OIDC) doit pouvoir lire le vault. Jamais de secret en clair dans Git.

Paramètres sécurisés vs fichiers

Un paramètre secureString masque la valeur dans les logs du portail et de certains outils, mais ne remplace pas Key Vault : la valeur peut encore circuler dans le pipeline ou l’historique local. Bonne pratique 2026 : paramètres non-secrets dans main.parameters.json versionné ; secrets via référence Key Vault ou injection runtime OIDC ; outputs limités aux IDs / noms publics. Si une clé a fuité une seule fois, regénérez-la sur le Storage Account (az storage account keys renew) avant de continuer.

Étape 5 — Déployer avec Azure CLI (what-if puis create)

cd ~/labs/ado-lab
git checkout -b feature/arm-templates-lab
mkdir -p infra
# placez main.json et main.parameters.json

az deployment group what-if 
  --resource-group rg-ado-lab-arm 
  --template-file infra/main.json 
  --parameters @infra/main.parameters.json

az deployment group create 
  --name deploy-arm-lab-001 
  --resource-group rg-ado-lab-arm 
  --template-file infra/main.json 
  --parameters @infra/main.parameters.json

az deployment group show 
  -g rg-ado-lab-arm -n deploy-arm-lab-001 
  --query properties.outputs -o json

az storage account list -g rg-ado-lab-arm -o table

what-if est la commande la plus utile : lisez le diff avant le create. Mode Incremental recommandé en lab.

Relire un déploiement

Après un create réussi :

az deployment group list -g rg-ado-lab-arm -o table
az deployment operation group list -g rg-ado-lab-arm -n deploy-arm-lab-001 -o table

En cas d’échec (nom Storage, apiVersion, RBAC), lisez properties.statusMessage, corrigez, puis redéployez (nouveau --name ou Incremental). L’idempotence ARM évite de tout recréer.

Étape 6 — Pipeline Azure Pipelines (AzureResourceManagerTemplateDeployment@3)

Stage infra avant l’app (release pipeline) ; Environments / approvals s’appliquent.

steps:
  - task: AzureResourceManagerTemplateDeployment@3
    displayName: Deploy ARM infra lab
    inputs:
      deploymentScope: Resource Group
      azureResourceManagerConnection: sc-ado-lab-oidc
      subscriptionId: $(subscriptionId)
      action: Create Or Update Resource Group
      resourceGroupName: rg-ado-lab-arm
      location: canadacentral
      templateLocation: Linked artifact
      csmFile: infra/main.json
      csmParametersFile: infra/main.parameters.json
      deploymentMode: Incremental
      deploymentOutputs: armOutputs

  - script: |
      echo "$(armOutputs)" | jq -r '.storageAccountName.value'
    displayName: Afficher nom Storage (pas de clés)

Ne loggez jamais de clés ; identité managée / Key Vault pour les secrets app.

Étape 7 — Équivalent Bicep (même lab, moins de bruit)

Microsoft recommande Bicep pour le neuf ; ARM JSON reste supporté (az bicep decompile / build).

// infra/main.bicep — équivalent lab ARM Storage
@description('Région lab P4 / IaC')
param location string = resourceGroup().location

@minLength(3)
@maxLength(11)
param storagePrefix string = 'stadolab'

@allowed(['Standard_LRS', 'Standard_GRS'])
param storageSku string = 'Standard_LRS'

var storageName = toLower('${storagePrefix}${uniqueString(resourceGroup().id)}')

resource stg 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageName
  location: location
  sku: { name: storageSku }
  kind: 'StorageV2'
  properties: {
    allowBlobPublicAccess: false
    minimumTlsVersion: 'TLS1_2'
    supportsHttpsTrafficOnly: true
  }
}

output storageAccountName string = stg.name
output storageAccountId string = stg.id
az deployment group what-if -g rg-ado-lab-arm --template-file infra/main.bicep
az deployment group create  -g rg-ado-lab-arm --template-file infra/main.bicep
# optionnel pédagogique : az bicep build -f infra/main.bicep

Voir aussi le chapitre dédié Bicep : premier template.

Étape 8 — ARM / Bicep vs Terraform (2026)

Critère ARM / Bicep Terraform (azurerm)
Cloud Azure-only Multi-cloud
État Azure = source de vérité State file (backend)
Nouveautés Azure Jour 1 (ARM) Provider / délai possible
Syntaxe JSON ou DSL Bicep HCL
Lab Azure-centré Oui (cette série) Valide si stack multi-cloud

Les deux sont valides en 2026 : Azure-first → Bicep souvent ; multi-cloud / Azure DevOps tools → Terraform. Ce chapitre ancre ARM (plan de contrôle Azure).

Lab bonus (8–10 min) — checklist

  1. Second what-if après create (Incremental) — peu/pas de Create.
  2. Région : az group show -n rg-ado-lab-arm --query location -o tsv → canadacentral.
  3. Outputs : nom + id seulement.
  4. Commit main.json / main.parameters.json / main.bicep sans secrets.
  5. Anti-dérive : Standard_LRS ; HTTPS/TLS 1.2 ; blob public off ; params = non-secrets.

  6. Relancez what-if après une modification mineure de tag : vous devez voir un Modify sur le Storage, pas un Delete.

  7. Vérifiez qu’aucun output ne contient listKeys, connectionString ou SAS.
  8. (Option) az bicep decompile -f infra/main.json pour comparer le JSON au DSL — puis gardez Bicep comme source de vérité pour le neuf.

Checklist anti-dérive IaC (mémo)

  1. Source de vérité = template versionné (JSON aujourd’hui, Bicep demain) — pas le portail « cliqué ».
  2. SKU cheap Standard_LRS ; HTTPS only ; TLS 1.2 ; blob public désactivé.
  3. Paramètres commités = non-secrets ; RG rg-ado-lab-arm en canadacentral.
  4. Pipeline : Incremental + what-if (ou revue) avant apply ; service connection OIDC, pas de secret client long-lived si possible.
  5. Fin de session : az group delete -n rg-ado-lab-arm -y --no-wait si plus besoin.

Scénario terrain

« Un collègue a mis P1v3 et une connection string Storage en clair dans le template “pour aller vite”. » → Storage LRS (ou Free/F1 très court), retirez les secrets, Key Vault + identité managée, régénérez les clés si fuite, imposez what-if + revue PR avant create. Coût et fuite s’arrêtent avant la prod.

Variante : mode Complete « pour nettoyer » un RG partagé peut supprimer des ressources hors template. Réservez Complete derrière environment + approvers, et lisez le what-if (Delete) avant d’appliquer.

Points clés à retenir

  • ARM est le plan de contrôle Azure : templates JSON déclaratifs, idempotents, déployés sur un scope.
  • parameters + variables + uniqueString rendent un template réutilisable sans collision de noms.
  • what-if puis create (Incremental) = boucle sûre en lab et en pipeline.
  • Secrets : Key Vault references / OIDC — jamais en clair dans Git ni en outputs publics.
  • Pour le neuf, écrivez en Bicep ; comprendre ARM reste indispensable pour lire les erreurs, les tâches pipeline et le legacy.

Erreurs fréquentes

Symptôme Cause Correction
StorageAccountAlreadyTaken / name invalid Nom global / règles Préfixe court + uniqueString
Location mismatch RG hors canadacentral Recréez rg-ado-lab-arm en Canada Central
NoRegisteredProviderFound / apiVersion Version API invalide Doc resource reference ; API Storage 2023-05-01
Circular dependency Deux ressources se référencent Casser la boucle / enfant / 2e déploiement
Parameter file rejected Mauvais $schema Schema deploymentParameters
AuthorizationFailed RBAC Contributor sur le RG ; OIDC service connection
Secrets dans parameters.json Copier-coller MDP Key Vault reference ; rotate si fuite
Mode Complete surprenant Ressources hors template supprimées Preférez Incremental en lab
Facture App Service inattendue Plan B1/P1v3 oublié Lab Storage only ; az group delete
uniqueString change après recreate RG Nouvel resourceGroup().id Attendu ; gardez le même RG ou mettez à jour les refs

Quiz (5 questions)

1. Quel est le rôle principal d’un template ARM ?
– A. Décrire déclarativement des ressources Azure en JSON (ou via Bicep → ARM)
– B. Remplacer Azure AD et MFA
– C. Stocker les PAT Azure DevOps dans le state

2. Quelle pratique est correcte pour ce lab Storage ?
– A. SKU Standard_LRS, HTTPS/TLS 1.2, outputs sans clés
– B. Output listKeys dans le README public
– C. Déployer un plan P1v3 sans budget

3. À quoi sert az deployment group what-if ?
– A. Prévisualiser Create/Modify/Delete avant d’appliquer
– B. Supprimer automatiquement le Key Vault
– C. Compiler Terraform vers ARM

4. Comment injecter un secret sans le mettre en clair dans le parameter file ?
– A. Référence Key Vault (reference.keyVault + secretName)
– B. Hardcoder le MDP dans variables
– C. Le coller dans un commentaire JSON

5. Pourquoi la série recommande-t-elle Bicep pour les nouveaux templates tout en enseignant ARM ?
– A. Bicep compile vers ARM, plus lisible ; comprendre ARM reste utile (pipeline, debug, legacy)
– B. ARM JSON est interdit depuis 2025
– C. Terraform ne fonctionne plus sur Azure

Réponses : 1‑A · 2‑A · 3‑A · 4‑A · 5‑A

Pour aller plus loin

Nettoyage

az group delete -n rg-ado-lab-arm -y --no-wait

Gardez infra/ dans Git pour les labs pipeline même si le RG est détruit.

Maillage série

← Précédent Azure Monitor / monitoring
→ Suivant Jenkins avec Azure Repos
Aussi Release pipeline · Azure DevOps tools · Bicep : premier template

Retour parcours Azure DevOps — hub de la série et leçons sœurs.

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *