Simplifier l’injection des paramètres dynamiques dans Azure Machine Configuration avec Terraform

par | Avr 14, 2026 | Uncategorized | 0 commentaires

Dans notre précédent article, nous avons vu comment Azure Machine Configuration permettait d’injecter dynamiquement des paramètres dans des configurations DSC génériques.
La mécanique fonctionne, mais personne n’utilise de template ARM pour gérer ses déploiements au quotidien!
Heureusement, la ressource azurerm_policy_virtual_machine_configuration_assignment du provider AzureRM de Terraform supporte également l’injection des paramètres via un ou plusieurs attributs « parameter » dans le bloc « configuration » :

resource "azurerm_policy_virtual_machine_configuration_assignment" "iis_config" {
  name               = "IIS_Standard"
  location           = azurerm_resource_group.rg.location
  virtual_machine_id = azurerm_windows_virtual_machine.web_server.id

  configuration {
    assignment_type = "ApplyAndAutoCorrect"
    version         = "1.0"
    content_uri     = "https://mystorage.blob.core.windows.net/configs/IIS.zip"
    content_hash    = "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6A7B8C9D0E1F2"

    parameter {
      name  = "[WebSite]MyCompanySite;PhysicalPath"
      value = "D:\\ProductionWeb\\MySite"
    }

    parameter {
      name  = "[WebSite]MyCompanySite;State"
      value = "Started"
    }

  parameter {
      name  = "[WindowsFeature]AspNet45;Ensure"
      value = "Present"
    }
  }
}

Le problème? Même si ce code est plus lisible qu’un template ARM en JSON, il souffre du même défaut structurel : la syntaxe name/value pour l’injection des paramètres est strictement la même, toujours aussi verbeuse et répétitive.
Le code n’en est pas moins fonctionnel, mais sa lisibilité devient douteuse lorsqu’il s’agit de configurer des déploiements complexes avec des dizaines de pramètres !

Mais contrairement à ARM, Terraform dispose d’une solution évidente pour améliorer la situation : les modules, qui permettent de simplifier la manipulation de structures complexes et répétitives. Mon objectif devient alors évident : créer un module qui permet la saisie de paramètres en suivant la syntaxe naturelle d’un script DSC, et laisser Terraform faire le travail de formatage complexe en coulisses.

Un exemple valant mieux qu’un long discours, voici la syntaxe souhaitée :

parameters = {
  "[WebSite]MyCompanySite" = {
     PhysicalPath = "D:\\ProductionWeb\\MySite"
     State        = "Started"
  }
}

Voilà qui est bien plus simple, lisible et proche de la syntaxe DSC d’origine!

Pour que les informations contenues dans cette structure (techniquement un dictionnaire de dictionnaires, ou map(map(string)) soit compréhensible par la ressource azurerm_policy_virtual_machine_configuration_assignment, notre module doit la transformer. Terraform propose pour cela des outils de manipulation de données très puissants : les boucles for imbriquées et la fonction flatten.

Voici le cœur du moteur de notre module (dans le fichier main.tf) :

resource "azurerm_policy_virtual_machine_configuration_assignment" "this" {
  for_each = local.guest_configurations_map

  name               = each.key
  location           = var.location
  virtual_machine_id = var.virtual_machine_id

  configuration {
    assignment_type = var.assignment_type
    version         = var.configuration_version
    content_uri     = each.value.content_uri
    content_hash    = each.value.content_hash

    dynamic "parameter" {
      for_each = flatten([
        for param_name, param_values in each.value.parameters : [
          for key, value in param_values : {
            name  = "${param_name};${key}"
            value = value
          }
        ]
      ])
      content {
        name  = parameter.value.name
        value = parameter.value.value
      }
    }
  }
}

Que se passe-t-il exactement ?

Terraform parcourt notre dictionnaire principal parameters (for param_name, param_values…).

Pour chaque ressource DSC trouvée (ex: [WebSite]MyCompanySite), il parcourt ses propriétés (for key, value…).

Il concatène dynamiquement la clé principale, un point-virgule et la sous-clé : name = « ${param_name};${key} ».

La fonction flatten « écrase » ces listes imbriquées pour en faire une liste simple à un seul niveau, qui va ensuite être parcourue de facon classique par le for_each du bloc dynamic et transformé en autant de blocs « parameter » que nécessaire.

Maintenant que notre module est prêt, son appel depuis notre code principal devient un jeu d’enfant. Non seulement nous pouvons gérer facilement les paramètres complexes, mais nous pouvons également assigner plusieurs packages DSC à la même machine virtuelle en une seule fois :

module "machine_configuration" {
  source  = "github.com/Cyr-Az/terraform-azurerm-cyraz-machine-configuration"
  # version = "x.x.x"

  virtual_machine_id = azurerm_windows_virtual_machine.example.id
  location           = azurerm_resource_group.example.location

  guest_configurations =[
    {
      name         = "IIS_Standard"
      content_uri  = "https://mystorage.blob.core.windows.net/configs/IIS_Standard.zip"
      content_hash = "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6A7B8C9D0E1F2"
      
      parameters = {
        "[WebSite]MyCompanySite" = {
          PhysicalPath = "D:\\ProductionWeb\\MySite"
          State        = "Started"
        }
        "[WindowsFeature]AspNet45" = {
          Ensure = "Present"
        }
      }
    },
    {
      name         = "Other_Config"
      content_uri  ="https://mystorage.blob.core.windows.net/configs/Other_Config.zip"
      content_hash = "B2C3D4E5..."

      parameters = {
        "[SomeResource]Name" = {
          Parameter = "Value"
        }
      }
    }
  ]
}

Vous pouvez retrouver ce module complet avec un example plus détaillé sur mon Github : Cyr-Az/terraform-azurerm-cyraz-machine-configuration: Terraform module to simplify Machine Configuration assignments with custom parameters

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *