Catégorie : Infrastructure as Code

Terraform, Bicep et OpenTofu : nouvelles versions, migrations de providers et bonnes pratiques pour tes modules Infrastructure as Code.

  • Terraform 1.17 passe en GA : Policy, et le vrai sujet caché dans le changelog

    Terraform 1.17 passe en GA : Policy, et le vrai sujet caché dans le changelog

    Terraform 1.17.0 est sorti le 21 octobre 2026. Le changelog met en avant le passage en disponibilité générale de Terraform Policy — logique, c’est la fonctionnalité qu’on suivait depuis la bêta début octobre. Mais la ligne la plus importante de ce changelog n’a rien à voir avec les policies : c’est celle qui dit que le binaire est désormais compilé avec Go 1.26.10, pour ne plus faire confiance à des certificats d’autorité de certification compromis.

    Terraform Policy quitte l’expérimental

    On avait couvert la bêta de cette fonctionnalité dans notre article sur Terraform 1.17 et ses policies HCL le 14 octobre. Deux semaines plus tard, le flag -policies disponible sur plan, apply et query n’a plus besoin d’un build expérimental ni du flag -allow-experimental-features — il est utilisable en production sans réserve.

    Les policies s’écrivent en HCL, dans des fichiers .policy.hcl — pas de nouveau langage à apprendre si tu connais déjà Terraform. La nouveauté de cette version concerne surtout query : les policies évaluées sur les ressources découvertes par un bloc list renvoient désormais correctement les statuts Unknown et N/A au lieu de résultats incohérents, un bug corrigé entre la bêta et le GA. La documentation officielle de Terraform Policy détaille la syntaxe complète si tu veux écrire tes premières règles.

    Pour qui venait de Sentinel ou d’OPA/Conftest en externe, l’intérêt n’est pas la puissance du langage — HCL reste plus limité qu’un vrai langage de politique comme Rego — mais l’intégration native : pas de binaire tiers à installer, pas de pipeline séparé à maintenir pour une politique simple de type « interdire les buckets publics » ou « exiger un tag owner« .

    -minimal-refresh : une option de planification à tester

    Moins visible dans les annonces, mais potentiellement plus utile au quotidien pour qui gère un state volumineux : la nouvelle option -minimal-refresh sur terraform plan limite le rafraîchissement aux seules ressources qui ont des changements proposés, au lieu de rafraîchir l’intégralité du state à chaque plan. Sur un state de plusieurs centaines de ressources où la majorité ne bouge jamais entre deux applies, ça peut réduire significativement le nombre d’appels API et le temps de plan — à vérifier sur ton propre state plutôt qu’à prendre pour argent comptant, le gain dépend entièrement de la proportion de ressources réellement stables.

    Le vrai sujet caché dans le changelog : les clés CA d’eMudhra

    Voici ce qui justifie une mise à jour même si tu n’utilises ni les policies ni -minimal-refresh. Le 17 octobre 2026, le chercheur Wayne a découvert que huit certificats intermédiaires de l’autorité de certification eMudhra utilisaient des clés privées P-384 anormalement faibles — récupérables en testant seulement 256 possibilités. Un autre chercheur, Flüpke, a publié l’une de ces clés sur GitHub pour démontrer le problème ; elle correspondait bien à un certificat révoqué.

    La cause : une erreur de script chez eMudhra a généré un second jeu de clés plus faibles en avril 2025, sélectionné par erreur pour la signature parce que ses libellés ressemblaient à ceux du bon jeu. Certains de ces certificats avaient même été soumis à Sectigo pour une cross-signature, élargissant la surface d’impact potentielle. eMudhra affirme que la plupart des intermédiaires concernés n’ont jamais servi en production et n’a trouvé aucune preuve qu’ils aient émis des certificats pour des utilisateurs finaux — mais la fenêtre d’exposition théorique court depuis avril 2025, sans garantie que personne n’en a profité.

    La réaction en cascade a été rapide : eMudhra a révoqué les huit certificats et arrêté l’émission sous sa racine G3, Mozilla a bloqué les certificats via OneCRL le 17 octobre puis sorti Firefox 158.0.1 le 20, Chrome a bloqué six intermédiaires le 17, Apple a ajouté ses propres protections le 22. L’équipe Go a réagi dans le même mouvement avec les versions 1.27.3 et 1.26.10, qui corrigent CVE-2026-111943 en retirant la confiance envers ces clés compromises. C’est cette version de Go — 1.26.10 — qui compile désormais Terraform 1.17.0, comme le détaille le changelog officiel sur GitHub.

    Le point à retenir ne se limite pas à Terraform : si tu as d’autres binaires Go dans ta chaîne d’outils (Docker, kubectl, Vault, ta propre CLI interne…), ils méritent la même vérification. Le détail complet de l’incident, timeline comprise, est couvert par BleepingComputer.

    Faut-il migrer tout de suite ?

    Pour un projet neuf, oui, sans hésiter : rien dans les notes de version ne signale de changement cassant, et les corrections de bugs de cette 1.17.0 (panique évitée sur les fonctions pow/log en cas de résultat infini, ordre déterministe du nettoyage des tests, diagnostics d’ephemeral resources enfin affichés au lieu d’être silencieusement perdus) sont toutes dans le sens de la stabilité, pas de la rupture.

    Pour un parc existant, la priorité dépend de ton usage : si tu es sur OpenTofu plutôt que Terraform, le sujet policies ne te concerne pas directement — on a détaillé les différences d’approche sur le chiffrement de state dans notre article sur OpenTofu 1.13 face à Terraform. Mais le correctif Go pour eMudhra, lui, concerne tout le monde qui fait confiance à un binaire Terraform pour parler en TLS à un provider cloud.

    FAQ

    Terraform Policy remplace-t-il Sentinel ou OPA ?
    Pas vraiment, plutôt une alternative native pour les cas simples. Sentinel reste propre à HCP Terraform/Terraform Enterprise, et OPA/Rego offre un langage de politique nettement plus expressif pour des règles complexes multi-ressources.

    Je n’utilise pas les policies, dois-je mettre à jour quand même ?
    Oui, pour le correctif Go lié à eMudhra. Si ton binaire Terraform communique en TLS avec un provider cloud, la version du runtime Go avec laquelle il a été compilé a une importance directe sur la confiance accordée à certains certificats.

    Le chiffrement de state a-t-il changé dans cette version ?
    Non, les notes de version de la 1.17.0 ne mentionnent aucune évolution sur ce point — la fonctionnalité de chiffrement de state existante n’est pas modifiée par cette sortie.

    En pratique

    terraform version te donne la version installée et le runtime Go associé en quelques secondes. Si tu gères plusieurs postes ou plusieurs runners CI, c’est le bon moment pour vérifier lesquels tournent encore sur un Go antérieur à 1.26.10 ou 1.27.3 — pas seulement pour Terraform, mais pour tout ce que ta chaîne d’outils fait tourner en Go.

  • OpenTofu 1.13 : le chiffrement de state face à Terraform

    OpenTofu 1.13 : le chiffrement de state face à Terraform

    Le 29 septembre 2026, OpenTofu a publié sa version 1.13. Le changelog tient en quatre fonctionnalités mises en avant et quatre changements cassants — rien de spectaculaire sur le papier. Sauf qu’en creusant la partie chiffrement du state, maintenue depuis plusieurs versions mais étendue ici, on retombe sur l’argument le plus concret en faveur d’OpenTofu face à Terraform depuis le fork lui-même : Terraform ne chiffre toujours pas nativement le contenu de son state. Voici ce qui change avec cette version, et pourquoi ça pèse dans la balance si tu hésites encore entre les deux outils.

    Ce qui change avec la 1.13

    Le chiffrement du state gagne trois mécanismes de contexte

    Le bloc encryption dans terraform { } existe depuis plusieurs versions. Sa structure reste la même : un ou plusieurs key_provider, une method qui référence ces clés, puis un bloc state et un bloc plan qui pointent vers cette méthode.

    terraform {
      encryption {
        key_provider "pbkdf2" "mykey" {
          passphrase = var.state_passphrase  # minimum 16 caractères
        }
        method "aes_gcm" "mymethod" {
          keys = key_provider.pbkdf2.mykey
        }
        state {
          method = method.aes_gcm.mymethod
        }
        plan {
          method = method.aes_gcm.mymethod
        }
      }
    }
    

    Les fournisseurs de clés supportés couvrent la quasi-totalité des cas réels : passphrase dérivée via PBKDF2, AWS KMS, GCP KMS, Azure Key Vault, le moteur Transit d’OpenBao (compatible HashiCorp Vault 1.14), et un provider générique external qui exécute ton propre programme — OVHcloud maintient d’ailleurs son propre provider KMS basé sur ce mécanisme.

    La vraie nouveauté de la 1.13 porte sur le contexte de déchiffrement. GCP KMS reçoit un champ additional_authenticated_data, AWS KMS un champ encryption_context, OpenBao un argument associated_data. Dans les trois cas, le principe est identique : la clé seule ne suffit plus à déchiffrer un state. Il faut aussi que le contexte (nom du projet, environnement, équipe…) corresponde. Concrètement, une clé AWS KMS volée ou mal cloisonnée entre deux comptes ne permet plus de déchiffrer le state d’un environnement qui n’est pas le sien.

    Le reste du changelog, en bref

    Windows ARM64 passe en support officiel, avec des binaires publiés directement (certains providers tiers ne suivent pas encore). La fonction convert permet de déclarer explicitement le type attendu d’une valeur inconnue au moment du plan — utile pour calmer le bruit des diffs quand un module retourne une valeur qui ne sera connue qu’à l’apply. Dans le même esprit, les fonctions assume... laissent l’auteur d’un module affirmer une propriété sur une valeur inconnue (non nulle, préfixe donné…) : si l’affirmation est fausse à l’apply, l’opération échoue plutôt que de produire un résultat silencieusement incohérent.

    Deux fonctionnalités expérimentales complètent la liste : un linter activable via le flag -lint sur les commandes qui le supportent, et des « Symbol Libraries », des artefacts réutilisables de valeurs, de fonctions et de types importables depuis les mêmes sources que les modules.

    Ce qui casse en mettant à jour

    Quatre points à vérifier avant de passer en 1.13 :

    • Le provisioner WinRM disparaît complètement pour remote-exec et file — un bloc connection avec type = "winrm" devient une erreur. OpenTofu recommande de migrer vers OpenSSH côté Windows.
    • La sortie de base64gzip change : elle reste équivalente, mais plus identique octet par octet, à cause d’une compression DEFLATE optimisée. Tu peux voir apparaître des diffs sur des arguments qui en dépendent — un ignore_changes temporaire fait l’affaire en attendant.
    • macOS 13 Ventura devient la version minimale supportée pour les builds macOS.
    • La 1.13 est la dernière série à publier des binaires 32 bits (386, arm) officiels — un avertissement s’affiche déjà sur tofu init sur ces plateformes, et la 1.14 ne les inclura plus.

    Et côté Terraform, qu’est-ce qui existe d’équivalent ?

    Rien. C’est la différence structurelle la plus nette entre les deux outils aujourd’hui. La documentation officielle de HashiCorp le dit sans détour : « tu peux chiffrer ton state au repos, mais la méthode de chiffrement dépend de ton backend spécifique ». Sur S3, ça veut dire activer l’option encrypt du backend. Sur GCS, utiliser des clés gérées par le client. Sur HCP Terraform, le chiffrement est automatique. En stockage local, le state reste un fichier en clair, point final — HashiCorp recommande juste de ne jamais le committer et de le traiter comme sensible.

    Ça fonctionne, mais ça reste un chiffrement de transport ou de stockage externe à l’outil, pas un chiffrement du contenu piloté par Terraform lui-même. Si ton backend est mal configuré, ou si quelqu’un récupère une copie du fichier state hors backend (un export, un backup oublié sur un poste), le contenu est lisible — secrets inclus, puisque le state contient souvent des valeurs sensibles en clair malgré les bonnes pratiques.

    On avait déjà creusé la question du choix entre les deux outils dans notre comparatif OpenTofu vs Terraform en 2026, à l’époque surtout sous l’angle licence et écosystème de providers. Un an plus tard, l’écart sur le chiffrement du state mérite d’être ajouté à la liste — pas comme argument décisif à lui seul, mais comme point concret si la sensibilité de ton state (comptes de service, mots de passe de bases de données, clés d’API) te pèse déjà.

    Migrer un projet existant vers le chiffrement OpenTofu

    La bascule n’a rien d’instantané ni d’automatique, et c’est volontaire. Ajoute le bloc encryption à ta configuration, génère une passphrase d’au moins 16 caractères (ou configure ton KMS), passe-la via une variable jamais committée — un coffre de secrets, pas un fichier .tfvars versionné. Au tofu plan suivant, OpenTofu re-chiffre le state existant selon la méthode déclarée ; garde une copie de l’ancien state en lieu sûr avant de lancer l’opération, histoire de pouvoir revenir en arrière si la configuration du provider de clé a un défaut que tu n’as pas vu venir.

    Pour des équipes qui partagent un seul backend entre plusieurs environnements — un cas plus courant qu’il ne devrait l’être, faute de temps pour en séparer les accès — ajouter encryption_context ou additional_authenticated_data dès cette migration coûte une ligne de configuration et change concrètement qui peut lire quoi en cas de fuite de clé.

    FAQ

    Faut-il absolument chiffrer son state si on utilise déjà un backend S3 avec encrypt = true ?

    Ça dépend de ce que tu veux couvrir. Le chiffrement du backend protège le fichier stocké sur S3. Le chiffrement OpenTofu protège le contenu lui-même, y compris s’il sort du backend — une copie locale, un export, un transfert. Les deux ne sont pas redondants, ils couvrent des scénarios de fuite différents.

    Le chiffrement ralentit-il les commandes plan et apply ?

    Le surcoût vient uniquement du chiffrement et du déchiffrement AES-GCM du fichier state, qui reste de taille modeste pour l’écrasante majorité des projets. Sur un state de plusieurs centaines de ressources, la différence n’est pas perceptible à l’usage.

    Est-ce que je peux migrer progressivement, environnement par environnement ?

    Oui, rien n’empêche d’activer le chiffrement sur un seul environnement d’abord — staging, par exemple — pour valider la configuration du key provider avant de la généraliser à la prod.

    OpenTofu 1.13 reste-t-il compatible avec un state produit par Terraform ?

    Oui pour la lecture d’un state existant non chiffré. La bascule vers le chiffrement OpenTofu est une étape volontaire que tu déclenches toi-même, pas un changement de format imposé à l’import.

    Si ton état actuel repose sur un simple encrypt = true côté backend et que tu veux passer à l’étape suivante, la note de version officielle 1.13.0 et le changelog complet sur GitHub listent tout le détail technique nécessaire avant de te lancer. Si tu es encore sur Terraform et que cet article te fait hésiter, on a aussi de quoi suivre ce que la 1.17 bêta de Terraform apporte de son côté avant de trancher.

  • Terraform 1.17 (bêta) : policies HCL hors expérimental

    Terraform 1.17 (bêta) : policies HCL hors expérimental

    Un administrateur bascule sur -allow-experimental-features pour tester un truc, oublie de le retirer, et six mois plus tard un collègue copie-colle le même flag en prod sans savoir pourquoi il est là. Ça t’est peut-être déjà arrivé avec Terraform : jusqu’à la version 1.16, impossible de vérifier des policies HCL au moment du plan ou de l’apply sans ce garde-fou expérimental. Terraform 1.17, actuellement en bêta, change ça — et en profite pour poser une vraie alternative à Sentinel et OPA.

    Le flag -policies quitte l’expérimental (mais pas tout le produit)

    Dans la liste des changements de la 1.17.0-beta1, un point mérite qu’on s’y arrête : le flag -policies disponible sur init, plan et apply ne nécessite plus -allow-experimental-features. Concrètement, tu peux désormais écrire une policy HCL et la brancher sur ton pipeline Terraform sans activer un mode qui te prévient à chaque exécution que tu utilises quelque chose d’instable.

    Attention à la nuance, parce qu’elle compte : c’est le support du flag dans le CLI Terraform qui sort de l’expérimental, pas le produit Terraform Policy lui-même. Sur la documentation officielle, HashiCorp est explicite : la fonctionnalité est en bêta publique, et la mention est sans ambiguïté — « do not use beta features in production environments ». Tu peux tester, documenter, préparer ta migration depuis Sentinel. Tu ne branches pas encore ça sur ton environnement de production critique.

    Terraform Policy, concrètement : ce qu’il fait que Sentinel et OPA ne font pas

    HashiCorp a annoncé ce nouveau framework le 16 juillet 2026 dans un billet intitulé « Introducing tfpolicy ». L’argument de vente tient en une phrase : écrire tes policies en HCL, le même langage que tes fichiers .tf, plutôt que d’apprendre le DSL Sentinel ou Rego pour OPA. Mais la vraie différence est ailleurs, dans ce que le moteur peut évaluer.

    Sentinel et OPA tournent uniquement au moment du plan, et ni l’un ni l’autre ne peut interroger une data source pendant l’évaluation — ils travaillent sur ce que le plan leur donne, point final. Terraform Policy, lui, peut s’exécuter à trois moments distincts du cycle de vie : pendant terraform init (avant même que les providers et modules soient téléchargés — utile pour bloquer un provider non approuvé avant qu’il touche ton disque), pendant le plan, et après l’apply, pour valider des valeurs qui ne sont connues qu’une fois la ressource provisionnée (un ARN généré par le provider, par exemple). Il peut aussi interroger des données externes au moment de l’évaluation — une liste d’AMI approuvées dans une data source, typiquement.

    Côté niveaux d’application, Sentinel propose advisory / soft-mandatory / hard-mandatory, OPA se limite à pass/fail sans niveau intermédiaire. Terraform Policy introduit un troisième modèle — advisory, mandatory_overridable et mandatory — qui se rapproche de Sentinel sans en reprendre le vocabulaire ni la syntaxe.

    Faut-il migrer tes policies Sentinel dès maintenant ?

    Non, et HashiCorp ne le demande pas. Le produit est en bêta publique sur HCP Terraform depuis juillet, le support CLI vient seulement de sortir de l’expérimental dans une version qui n’est elle-même pas encore stable. Si tu as un parc de policies Sentinel qui fonctionne, le bon réflexe est de suivre l’évolution, éventuellement de tester tfpolicy sur un projet non critique via l’agent skill GitHub mentionné dans l’annonce (conçu pour convertir des policies Sentinel existantes), mais pas de basculer ta gouvernance de prod sur un outil encore en bêta. OpenTofu, pour rappel, n’a pas d’équivalent annoncé à ce jour — un point à peser si la gouvernance par policy fait partie de tes critères de choix entre les deux outils.

    Les autres nouveautés de la 1.17 à ne pas manquer

    Terraform Policy capte l’attention, mais la bêta embarque trois autres changements utiles au quotidien.

    Les variables et les locals sont désormais supportés dans les required_providers — tu peux enfin centraliser une contrainte de version de provider dans une variable plutôt que de la dupliquer dans chaque bloc. Une nouvelle option de planification, -minimal-refresh, rafraîchit uniquement les ressources qui ont des changements proposés au lieu de l’état entier — un gain de temps net sur les configurations avec des centaines de ressources où seule une poignée bouge réellement. Et côté tests, mock_provider prend désormais en charge les ressources éphémères, ce qui évite de devoir provisionner un vrai secret juste pour faire tourner ta suite de tests.

    Un dernier détail technique : la sortie JSON de la commande version gagne un champ format_version. HashiCorp précise que ça ne devrait pas casser les intégrations existantes, mais recommande de vérifier ce champ dans les prochaines versions — un signe que d’autres changements de format sont probablement à venir.

    FAQ

    Terraform 1.17 est-elle disponible en version stable ?

    Non, au moment de la rédaction de cet article la dernière version publiée est la 1.17.0-beta1. La 1.16 reste la version stable recommandée pour la production — on avait détaillé ses apports (import dans les modules, destroy = false) à sa sortie début octobre.

    Terraform Policy remplace-t-il Sentinel ?

    Pas à ce stade. Sentinel reste pris en charge sur HCP Terraform et Terraform Enterprise. Terraform Policy est une alternative construite sur une philosophie différente (HCL plutôt qu’un DSL dédié, évaluation à plusieurs étapes du cycle de vie plutôt qu’au plan uniquement), pas un remplacement annoncé.

    Le flag -policies fonctionne-t-il avec OPA ou Sentinel ?

    Non, ce flag sert spécifiquement à activer les policies HCL de Terraform Policy en local, via le CLI open source. Sentinel et OPA restent gérés via HCP Terraform et Terraform Enterprise, avec leurs propres mécanismes d’activation.

    Passe à l’action

    Si tu gères des policies Sentinel aujourd’hui, le plus utile à faire cette semaine n’est pas de migrer quoi que ce soit : c’est de lire la page de comparaison HashiCorp et de repérer les deux ou trois règles de ton catalogue qui bénéficieraient le plus d’une évaluation post-apply ou d’une data source externe — ce sont elles qui justifieront un vrai test de tfpolicy quand la 1.17 passera stable. En attendant, reste sur la 1.16 pour tout ce qui touche à la production.

  • Terraform 1.16 : import dans les modules et destroy = false

    Terraform 1.16 : import dans les modules et destroy = false

    Jusqu’à Terraform 1.15, un bloc import ne pouvait vivre que dans le module racine. Si tu voulais reprendre la main sur un groupe de ressources créé à la main et géré ensuite par un module, tu devais écrire depuis la racine des adresses comme module.network.azurerm_virtual_network.main, et le module lui-même ne savait rien de cette adoption. Terraform 1.16, publié le 26 août 2026 et suivi de la 1.16.1 le 2 septembre, lève cette limite.

    Ce n’est pas la seule nouveauté utile. Voici ce qui change vraiment pour un usage quotidien sur Azure, ce qui mérite d’être testé avant d’y croire, et le seul point de vigilance de la montée de version.

    Les blocs import acceptés dans les modules

    Les notes de version de la 1.16.0 l’annoncent en une ligne (#38352) : les blocs import sont désormais supportés à l’intérieur des modules. Concrètement, un module peut porter lui-même l’adoption de ressources existantes :

    # modules/resource-group/main.tf
    resource "azurerm_resource_group" "this" {
      name     = var.name
      location = var.location
    }
    
    import {
      to = azurerm_resource_group.this
      id = "/subscriptions/${var.subscription_id}/resourceGroups/${var.name}"
    }

    Le même lot corrige un bug gênant : les blocs import respectent maintenant les noms locaux de providers (#38338). Si tu utilises des alias du type azurerm.hub pour cibler un autre abonnement, c’était une source d’erreurs.

    Mon avis : c’est un vrai gain pour les projets de reprise d’existant (landing zone, migration d’un parc fait au portail), mais ne laisse pas de bloc import en dur dans un module partagé entre plusieurs équipes. Chaque appelant hériterait d’une tentative d’import qui n’a de sens que pour toi. Garde ces blocs dans un module d’adoption dédié, ou retire-les une fois l’import fait. Teste aussi le comportement avec un module appelé en count ou for_each sur un terraform plan avant de généraliser.

    lifecycle { destroy = false } : ce que prevent_destroy ne faisait pas

    Nouveauté de la 1.16 (#38784), le bloc lifecycle d’une ressource accepte maintenant destroy = false. La documentation du méta-argument lifecycle le décrit ainsi : la ressource est retirée de l’état sans que l’infrastructure réelle soit détruite.

    resource "azurerm_storage_account" "legacy_logs" {
      name                     = "stlegacylogs001"
      resource_group_name      = azurerm_resource_group.this.name
      location                 = azurerm_resource_group.this.location
      account_tier             = "Standard"
      account_replication_type = "GRS"
    
      lifecycle {
        destroy = false
      }
    }

    La différence avec prevent_destroy est importante. prevent_destroy = true fait échouer le plan dès qu’une destruction est prévue, mais la doc rappelle qu’il ne protège rien si tu supprimes la configuration de la ressource. destroy = false fait autre chose : Terraform « oublie » la ressource au lieu de la supprimer. C’est exactement ce que tu veux quand une ressource passe sous la gestion d’une autre équipe ou d’une autre stack.

    Un bémol : la documentation reste laconique sur les cas limites, en particulier le remplacement forcé (un changement d’attribut qui impose une recréation). Valide le comportement sur ton cas avec un terraform plan en environnement de test avant de compter dessus en production. Pour une ressource que tu ne dois jamais perdre, garde un verrou Azure (CanNotDelete) en plus : c’est la seule protection qui ne dépend pas de l’outil.

    Le bloc store de terraform_data

    Les valeurs éphémères (arrivées en 1.10) ont un défaut assumé : elles ne survivent pas entre le plan et l’apply. Le nouveau bloc store de terraform_data (#38298) permet de les conserver. L’exemple de la documentation de terraform_data :

    ephemeral "random_password" "test" {
      length = 16
    }
    
    resource "terraform_data" "test" {
      store {
        input     = ephemeral.random_password.test.result
        sensitive = true
        version   = 1
      }
    }
    
    output "password" {
      sensitive = true
      value     = terraform_data.test.store.sensitive_output
    }

    L’argument version est la subtilité à retenir : tant que tu ne l’incrémentes pas, une nouvelle valeur d’input ne remplace pas la sortie stockée. Ça t’évite de régénérer un mot de passe à chaque plan.

    Attention au revers : stocker une valeur, c’est l’écrire dans l’état, même marquée sensitive. Les valeurs éphémères ont été créées justement pour ne plus y mettre de secrets. Utilise store seulement quand tu en as vraiment besoin, et seulement avec un backend chiffré et des droits d’accès serrés sur le state (pour un backend azurerm, un compte de stockage avec RBAC Entra et sans clé d’accès partagée).

    Les petites améliorations qui changent le quotidien

    • terraform state show -json et terraform workspace list -json produisent enfin une sortie exploitable par un script, sans parser du texte.
    • terraform graph -format=mermaid sort le graphe de dépendances en Mermaid : tu peux le coller tel quel dans un README GitHub ou un wiki Azure DevOps, qui savent l’afficher.
    • terraform console -scope=module.network évalue tes expressions dans le contexte d’un module. Pratique pour déboguer un locals compliqué sans tout remonter à la racine.
    • contains() sait tester la valeur null, et merge() ne plante plus quand on lui passe des objets null.
    • terraform test liste maintenant les ressources laissées en place quand skip_cleanup est activé.
    • Les namespaces de providers avec underscore sont acceptés (#38894), ce qui débloque certains registres privés.

    Avant de monter de version

    La seule note de mise à niveau concerne les provisioners : bastion_host_key est désormais réellement appliqué (#38318). Si tu utilises encore des provisioners remote-exec ou file via un bastion SSH, vérifie que la clé configurée est la bonne. Jusqu’ici, une valeur fausse passait inaperçue. Après la mise à jour, la connexion échouera.

    Pour le reste, la montée depuis 1.15 se fait sans réécriture. Prends directement le dernier patch (1.16.1 à ce jour) et contrains la version dans tes modules racines :

    terraform {
      required_version = ">= 1.16.1, < 1.17.0"
    }

    La 1.17 est déjà en alpha (build 1.17.0-alpha20260827), donc ne t’étonne pas de voir passer de nouvelles fonctions dans les prochains mois. Si tu es en train de te demander s’il faut rester sur Terraform ou passer à OpenTofu, j’ai fait le point dans OpenTofu vs Terraform en 2026.

    FAQ

    Mes configurations 1.15 fonctionnent-elles telles quelles ?

    Oui, à l’exception du cas bastion_host_key décrit plus haut. Fais quand même un terraform plan sur chaque stack après la mise à jour et vérifie qu’il ne propose aucun changement.

    Faut-il retirer un bloc import une fois la ressource importée ?

    Un bloc import dont la cible est déjà dans l’état ne fait plus rien, donc le garder ne casse rien. Le retirer rend le code plus lisible et évite qu’un futur lecteur se demande quelle ressource est encore « en adoption ».

    destroy = false ou bloc removed ?

    Le bloc removed (depuis 1.7) sert quand tu supprimes la ressource de ta configuration. destroy = false se pose sur la ressource elle-même, tant qu’elle est encore déclarée. Pour un transfert ponctuel vers une autre stack, removed reste le plus explicite.

    Ces nouveautés concernent-elles le provider AzureRM ?

    Non, elles sont dans le cœur de Terraform et marchent avec tous les providers. Côté AzureRM, la grosse évolution de l’année reste la version 5.0, dont j’ai détaillé la migration.

    Par où commencer

    Mets à jour Terraform sur ton poste et ton runner CI, lance un plan sur ta stack la plus simple, puis cherche dans ton code les terraform state rm lancés à la main dans des scripts ou des runbooks : ce sont les premiers candidats à remplacer par destroy = false ou un bloc removed, versionnés et relus comme le reste.

  • bicep docs : la commande qui génère enfin la doc de tes modules Bicep

    bicep docs : la commande qui génère enfin la doc de tes modules Bicep

    Un README de module Bicep périmé, c’est le genre de dette technique dont personne ne parle jusqu’au jour où un collègue déploie avec le mauvais paramètre parce que la doc listait encore l’ancienne valeur par défaut. Jusqu’ici, la seule option sérieuse pour éviter ça était le script PowerShell Set-AVMModule maintenu par l’équipe Azure Verified Modules — efficace, mais pensé pour leur propre dépôt, pas pour ton repo Bicep perso. Depuis le 24 septembre 2026, il existe enfin une réponse native côté CLI : bicep docs.

    Ce que fait la commande

    La commande génère un fichier README.md directement à partir de ton code Bicep, sans que tu aies à écrire la moindre ligne de documentation à la main. Elle extrait et met en forme :

    • les métadonnées du module (nom, description, si tu les as renseignées via metadata) ;
    • la liste des ressources Azure déployées ;
    • un tableau des paramètres avec type, caractère obligatoire ou non, et description ;
    • un tableau des outputs ;
    • les types exportés, variables et fonctions définies dans le module, quand il y en a.

    Elle est disponible dans la Bicep CLI à partir de la version 0.47.16. Vérifie la tienne avec bicep --version avant de te lancer — aucun flag expérimental à activer dans bicepconfig.json, la commande est directement utilisable une fois le binaire à jour.

    L’utiliser au quotidien

    La syntaxe de base ne demande rien de plus que le chemin du fichier :

    bicep docs generate ./main.bicep

    Par défaut, elle écrit un README.md à côté du fichier source. Trois options couvrent la quasi-totalité des cas réels :

    # Afficher le résultat dans le terminal sans écrire de fichier
    bicep docs generate ./main.bicep --stdout
    
    # Choisir précisément le nom et l'emplacement du fichier
    bicep docs generate ./main.bicep --outfile docs/README.md
    
    # Traiter tous les modules d'un dépôt en une seule commande
    bicep docs generate './modules/**/main.bicep'

    Ce dernier exemple avec --pattern est à mon avis le plus intéressant des trois : il transforme la commande en étape de pipeline. Tu peux l’ajouter dans un job GitHub Actions qui tourne à chaque pull request touchant un fichier .bicep, et faire échouer le build si le README généré diverge de celui commité — exactement le même principe qu’un terraform fmt -check, mais pour la documentation.

    Personnaliser le format avec Scriban

    Le README par défaut ne te plaît pas tel quel ? La génération repose sur Scriban, un langage de templating léger déjà utilisé ailleurs dans l’écosystème .NET. Tu peux fournir ton propre modèle via bicepconfig.json :

    {
      "documentation": {
        "template": {
          "file": "templates/readme.scriban"
        }
      }
    }

    Et injecter des valeurs supplémentaires dans le template avec --custom-template-value (pour une valeur isolée) ou --custom-template-value-file-path (pour un lot de valeurs depuis un fichier). De quoi, par exemple, ajouter automatiquement un lien vers ton wiki interne ou un badge de statut de pipeline en haut de chaque README généré.

    Le point qu’il ne faut pas perdre de vue

    La fonctionnalité est encore marquée comme expérimentale par Microsoft. Ça ne veut pas dire qu’elle est buguée — elle fonctionne bien dans mes tests — mais que les noms d’options, la structure du bicepconfig.json et le modèle de template par défaut peuvent changer d’une version à l’autre sans garantie de compatibilité ascendante. Si tu l’intègres dans un pipeline de CI, épingle la version de la Bicep CLI que tu utilises plutôt que de pointer vers la dernière disponible, histoire d’éviter qu’un README généré change de structure sans prévenir un lundi matin.

    Pour un module publié publiquement ou partagé entre plusieurs équipes, je recommande clairement d’adopter la commande maintenant : le gain de cohérence dépasse largement le risque de devoir ajuster deux ou trois options dans six mois. Pour un module strictement interne et peu réutilisé, tu peux attendre que la fonctionnalité sorte de son statut expérimental sans rien perdre.

    FAQ

    Est-ce que ça remplace Set-AVMModule pour les modules Azure Verified Modules ?

    Pas entièrement pour l’instant. Le script Set-AVMModule gère aussi la validation de la structure de dossiers et la compilation du template, en plus du README. bicep docs ne fait que la partie documentation, mais le fait nativement, sans dépendance à un script PowerShell externe.

    La commande fonctionne-t-elle aussi via Azure CLI (az bicep) ?

    Au moment de la rédaction, bicep docs n’apparaît pas encore dans la liste des sous-commandes az bicep documentées officiellement. Utilise directement le binaire Bicep CLI autonome en attendant une éventuelle intégration.

    Que se passe-t-il si mon module utilise des imports compile-time ou des types définis par l’utilisateur ?

    Ces éléments activent la génération de code en langageVersion 2.0, ce qui n’empêche pas bicep docs de fonctionner — les types exportés sont justement l’une des sections que la commande documente. On en parlait d’ailleurs en détail dans notre article sur les types définis par l’utilisateur en Bicep.

    Pour aller plus loin

    Si tu gères une bibliothèque de modules Bicep internes sur le modèle des Azure Verified Modules, bicep docs est le genre de petit outil qui change vraiment le quotidien une fois automatisé dans la CI. Notre article sur le passage aux Azure Verified Modules explique pourquoi cette discipline de documentation compte autant que le code lui-même dès que plusieurs équipes consomment les mêmes modules. Installe la dernière Bicep CLI, lance bicep docs generate sur ton dépôt existant, et regarde ce qui en sort — il y a de bonnes chances que tu découvres au passage un paramètre que personne n’avait documenté depuis des mois.

  • Types définis en Bicep : la fonctionnalité qui muscle tes modules IaC

    Types définis en Bicep : la fonctionnalité qui muscle tes modules IaC

    Un paramètre Bicep mal orthographié ne plante pas toujours ton déploiement. Écris otionalProperty au lieu de optionalProperty dans un objet de configuration, et par défaut, Bicep se contente d’un avertissement BCP089 — le déploiement continue, la propriété correcte reste vide, et tu découvres le problème en production plutôt qu’en revue de code. C’est exactement le genre de bug que les types définis par l’utilisateur, disponibles depuis la CLI Bicep 0.12, permettent d’éliminer, à condition de connaître les bons décorateurs.

    Le problème que @allowed et les commentaires ne résolvent qu’à moitié

    La façon classique de contraindre un paramètre Bicep, c’est le décorateur @allowed directement sur le paramètre :

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

    Ça fonctionne pour un paramètre isolé. Mais dès que tu veux réutiliser cette contrainte dans plusieurs modules — le SKU d’un compte de stockage revient dans presque tous les modules d’une landing zone —, tu recopies le même bloc @allowed partout, avec le risque qu’une équipe l’oublie ou le fasse dériver légèrement d’un module à l’autre. Les types définis par l’utilisateur déplacent cette contrainte dans un type nommé, réutilisable et exportable.

    Déclarer un type et le rendre solide

    La syntaxe de base est courte, comme le montre la documentation officielle des types définis par l’utilisateur :

    type storageAccountSkuType = 'Standard_LRS' | 'Standard_GRS'
    
    type storageAccountConfigType = {
      name: string
      sku: storageAccountSkuType
    }
    
    param storageAccountConfig storageAccountConfigType

    Ce qui rend ces types utiles en pratique, ce sont les décorateurs qu’on peut leur attacher. Ils vivent dans le namespace sys, donc en cas de conflit de nom tu peux toujours forcer sys.description() :

    • @minLength() / @maxLength() — bornes inclusives sur des chaînes ou des tableaux.
    • @minValue() / @maxValue() — bornes inclusives sur des entiers.
    • @secure() — masque la valeur dans l’historique de déploiement, applicable aux chaînes comme aux objets entiers.
    • @description() — accepte du Markdown, utile pour la documentation générée automatiquement.
    • @sealed() — transforme un avertissement de propriété inconnue en erreur bloquante. C’est le plus rentable des cinq, et il mérite sa propre section.

    @sealed() : le décorateur qui aurait évité le bug d’introduction

    Reprenons l’exemple du typo. Sans @sealed() :

    type anObject = {
      property: string
      optionalProperty: string?
    }
    
    param aParameter anObject = {
      property: 'value'
      otionalProperty: 'value'  // typo : simple avertissement BCP089, le déploiement continue
    }

    Avec @sealed() sur le type, ou directement sur le paramètre, la même faute de frappe devient une erreur de compilation, pas un warning noyé dans la sortie de az deployment :

    @sealed()
    type anObject = {
      property: string
      optionalProperty: string?
    }

    Sur un module partagé entre plusieurs équipes, ce n’est pas du perfectionnisme : c’est la différence entre un déploiement qui échoue tout de suite en pipeline et une ressource mal configurée qui passe une revue de code sans que personne ne le remarque. Il n’y a pas vraiment de cas où @sealed() coûte plus qu’il ne rapporte sur un type destiné à être réutilisé — mets-le par défaut, et retire-le seulement si un module a explicitement besoin de propriétés libres.

    Unions discriminées : un seul paramètre, plusieurs formes possibles

    Depuis la CLI 0.21, @discriminator() permet de typer un paramètre qui peut prendre plusieurs formes selon une propriété pivot. Pratique pour des modules qui exposent plusieurs modes de configuration sous un seul nom de paramètre :

    type FooConfig = {
      type: 'foo'
      value: int
    }
    
    type BarConfig = {
      type: 'bar'
      value: bool
    }
    
    @discriminator('type')
    type ServiceConfig = FooConfig | BarConfig
    
    param serviceConfig ServiceConfig = { type: 'bar', value: true }

    Bicep sait alors que si type vaut 'bar', value doit être un booléen, et le signale à la compilation si tu passes un entier par erreur, plutôt qu’à l’exécution côté Azure Resource Manager.

    Types dérivés de ressources : la nouveauté qui évite de deviner le schéma

    Fonctionnalité plus récente, CLI 0.34.1 minimum, les types dérivés de ressources extraient directement le schéma d’un type de ressource Azure, sans que tu aies à le recopier à la main :

    param storageAccountProps resourceInput<'Microsoft.Storage/storageAccounts@2023-01-01'>.properties = {
      accessTier: 'Hot'
      minimumTlsVersion: 'TLS1_2'
      allowBlobPublicAccess: false
      supportsHttpsTrafficOnly: true
    }
    
    resource storageAccount 'Microsoft.Storage/storageAccounts@2025-06-01' = {
      name: 'mystorageacct123'
      location: resourceGroup().location
      sku: {
        name: 'Standard_LRS'
      }
      kind: 'StorageV2'
      properties: storageAccountProps
    }

    resourceInput<...> expose les propriétés éditables, hors champs en lecture seule ; resourceOutput<...> fait l’inverse pour typer une sortie. Une nuance à garder en tête : cette vérification est faite à l’édition et à la compilation, pas imposée par le service ARM au moment du déploiement. Un @sealed() explicite reste donc le seul mécanisme qui bloque réellement un déploiement non conforme côté Azure.

    Exporter des types pour arrêter de les redéfinir dans chaque module

    Une fois qu’un type est stabilisé, @export() le rend disponible à l’import depuis d’autres fichiers Bicep :

    @export()
    type storageAccountSkuType = 'Standard_LRS' | 'Standard_GRS'
    
    @export()
    type storageAccountConfigType = {
      name: string
      sku: storageAccountSkuType
    }

    Si ton équipe a déjà investi dans les Azure Verified Modules pour standardiser ses landing zones, exporter les types utilisés par ces modules dans un fichier partagé règle exactement le problème que l’AVM tente de résoudre de son côté : deux équipes qui redéfinissent le même objet de configuration avec des contraintes légèrement différentes, jusqu’à ce qu’un déploiement échoue pour une raison que personne ne retrouve rapidement.

    FAQ

    Faut-il une version particulière de Bicep CLI pour utiliser tout ça ?

    Les types de base fonctionnent dès la CLI 0.12.X. Les unions discriminées (@discriminator()) demandent la 0.21.X, et les types dérivés de ressources (resourceInput/resourceOutput) la 0.34.1 au minimum — vérifie ta version avec az bicep version avant de t’appuyer dessus dans un pipeline partagé.

    Un type récursif est-il possible en Bicep ?

    Oui, mais seulement si au moins un chemin vers l’appel récursif est optionnel. Un type où chaque niveau imbriqué référence obligatoirement le suivant, sans jamais de propriété optionnelle, ne compile pas.

    Terraform a-t-il un équivalent direct ?

    Pas vraiment sous cette forme : Terraform valide surtout via des blocs variable avec validation, sans système de types nommés et exportables aussi proche de TypeScript. Si le choix entre les deux outils se pose encore chez toi, on avait détaillé les critères dans notre comparatif Terraform vs Bicep.

    Rien de tout ça ne demande de réécrire tes modules existants d’un coup. Commence par sceller (@sealed()) les objets de configuration les plus copiés-collés dans ton dépôt, et exporte-les au fur et à mesure que tu les stabilises. C’est le genre de changement qui ne se voit dans aucune démo, mais qui t’évite un ticket de support un vendredi soir.

  • OpenTofu vs Terraform en 2026 : faut-il vraiment migrer ?

    OpenTofu vs Terraform en 2026 : faut-il vraiment migrer ?

    Depuis que HashiCorp a fait basculer Terraform sous licence BSL fin 2023, puis a été racheté par IBM début 2025, la question revient régulièrement en équipe infra : est-ce qu’on migre vers OpenTofu, le fork open source ? Trois ans après le fork, le projet a mûri, gagné des fonctionnalités que Terraform n’a pas, et l’adoption progresse — mais pas de façon uniforme. Voici où en sont vraiment les choses en 2026, sans survendre, pour t’aider à trancher sereinement.

    Pourquoi ce fork existe (rappel rapide)

    La licence Business Source License (BSL) 1.1 adoptée par HashiCorp restreint l’usage commercial de Terraform pour tout produit qui viendrait concurrencer directement les offres HashiCorp (Terraform Cloud, Terraform Enterprise). En réaction, la Linux Foundation a lancé OpenTofu, un fork sous licence réellement open source (Mozilla Public License 2.0), porté par une communauté incluant des poids lourds comme Gruntwork, Spacelift, Scalr, Harness ou env0. Le code source complet est disponible sur le dépôt GitHub officiel du projet. Le rachat de HashiCorp par IBM début 2025 a accéléré le mouvement : plusieurs plateformes majeures, dont GitLab, ont depuis fait d’OpenTofu leur moteur recommandé par défaut pour éliminer toute dépendance à un éditeur propriétaire unique.

    Où en est l’adoption, vraiment, en 2026 ?

    C’est là qu’il faut être honnête plutôt que de reprendre les chiffres les plus flatteurs. Il existe en réalité trois niveaux de lecture bien différents :

    • Sur des plateformes qui ont fait le choix éditorial de pousser OpenTofu par défaut, comme le montre l’analyse de Scalr, la bascule est massive : environ 63 % des exécutions compatibles Terraform tournent désormais sous OpenTofu sur leur plateforme, et jusqu’à 72 % des nouveaux espaces de travail créés.
    • À l’échelle du marché global, les études indépendantes (CodeOxi, avril 2026) situent l’adoption d’OpenTofu autour de 12 % — un chiffre bien plus modeste.
    • Et surtout, le nombre d’organisations ayant réellement terminé une migration complète reste faible, de l’ordre de 5 % selon une étude Firefly.

    Autrement dit : beaucoup d’équipes testent, certaines plateformes poussent fort dans cette direction, mais la migration effective en production reste encore minoritaire. Ce n’est pas une raison pour l’ignorer — c’est une raison de l’évaluer avec les bons critères plutôt que par effet de mode.

    Les vrais avantages techniques d’OpenTofu aujourd’hui

    Indépendamment du débat de licence, OpenTofu a ajouté plusieurs fonctionnalités concrètes que Terraform n’a pas (ou pas encore) :

    • Chiffrement natif de l’état (depuis la v1.7) : le fichier .tfstate peut être chiffré nativement, sans dépendre d’un backend spécifique déjà chiffré côté stockage.
    • Itération de providers avec for_each : tu peux désormais configurer plusieurs instances d’un même provider dynamiquement, utile pour du multi-région ou multi-compte géré en boucle.
    • Le flag -exclude sur plan/apply, pour exclure précisément certaines ressources d’une exécution — le complément logique du -target déjà existant.
    • Support des registres OCI pour distribuer modules et providers, ce qui te permet de réutiliser l’infrastructure de registre de conteneurs que tu as probablement déjà (Azure Container Registry, par exemple).
    • Verrouillage d’état S3 natif, sans dépendance à une table DynamoDB séparée — une simplification bienvenue si ton backend est S3-compatible.

    Exemple de bloc de chiffrement d’état, une fonctionnalité qui n’existe pas nativement côté Terraform :

    terraform {
      encryption {
        key_provider "pbkdf2" "monkey" {
          passphrase = var.state_encryption_passphrase
        }
        method "aes_gcm" "monmethode" {
          keys = key_provider.pbkdf2.monkey
        }
        state {
          method = method.aes_gcm.monmethode
        }
      }
    }
    

    Et côté Azure ? La compatibilité avec les Azure Verified Modules

    Si tu déploies sur Azure, tu utilises probablement déjà (ou tu devrais) les Azure Verified Modules (AVM), les modules IaC officiels maintenus par Microsoft pour Bicep et Terraform. Ces modules sont testés et « vérifiés » spécifiquement pour Terraform — pas explicitement pour OpenTofu. Dans la pratique, grâce à la compatibilité de syntaxe HCL et de format d’état, la très grande majorité des modules AVM Terraform fonctionnent tels quels sous OpenTofu. Mais comme ce n’est pas une garantie officielle de Microsoft, teste systématiquement en environnement non-critique avant de généraliser, surtout sur les modules qui utilisent des fonctionnalités provider récentes.

    Faut-il migrer ? Une grille de décision simple

    • Tu es en infrastructure auto-hébergée, sensible aux coûts de licence, et tu veux éliminer toute dépendance à un éditeur unique : OpenTofu a du sens.
    • Tu utilises fortement Terraform Cloud/Enterprise ou l’intégration HCP : le bénéfice immédiat est plus faible, sauf si tu prévois justement de t’en détacher.
    • Tu débutes un nouveau projet : c’est le moment le plus simple pour trancher, sans dette de migration à gérer.

    Bonne nouvelle technique : la migration reste globalement peu douloureuse. Le format d’état est compatible, la syntaxe HCL ne change pas, et le binaire tofu se comporte comme un remplacement quasi direct de terraform dans la plupart des pipelines CI/CD.

    FAQ

    OpenTofu est-il 100 % compatible avec mes fichiers Terraform existants ?

    Dans l’immense majorité des cas, oui — la syntaxe HCL et le format d’état sont compatibles. Les divergences apparaissent surtout sur les fonctionnalités ajoutées après le fork (chiffrement d’état, registres OCI), qui n’ont pas d’équivalent côté Terraform.

    Puis-je utiliser des providers Terraform officiels avec OpenTofu ?

    Oui, OpenTofu reste compatible avec le protocole de providers Terraform : tu continues à utiliser les providers du registre public sans modification.

    Terraform va-t-il disparaître ?

    Rien ne l’indique. Terraform reste largement utilisé et activement développé par HashiCorp/IBM. La question n’est pas « lequel va survivre » mais « lequel correspond le mieux à tes contraintes de licence et à ton besoin d’indépendance vis-à-vis d’un éditeur ».

    Si le choix de l’outil IaC en général te travaille encore, notre comparatif Terraform ou Bicep en 2026 complète bien cette réflexion côté Azure, et notre guide de migration vers AzureRM 5.0 reste valable que tu restes sur Terraform ou que tu passes à OpenTofu, puisque le provider ne change pas.

  • Terraform ou Bicep en 2026 : lequel choisir pour Azure ?

    Terraform ou Bicep en 2026 : lequel choisir pour Azure ?

    Terraform ou Bicep pour tes déploiements Azure ? Si tu te poses encore la question en 2026, tu n’es pas en retard — c’est même le bon moment pour trancher, parce que les deux outils ont beaucoup évolué depuis 2024 et l’écart entre eux s’est réduit sur plusieurs points qui faisaient historiquement pencher la balance. Dans cet article, on fait le point sur ce qui a vraiment changé, les forces et limites actuelles de chaque outil, et comment choisir sans te tromper selon ton contexte.

    Ce qui a changé depuis 2024-2025

    Quatre évolutions ont rebattu les cartes :

    • Les deployment stacks donnent enfin à Bicep une vraie gestion du cycle de vie complet des ressources (création, mise à jour, et surtout suppression propre des ressources qui sortent du template), ce qui comblait un manque réel face au terraform destroy.
    • Les Azure Verified Modules (AVM) couvrent désormais les deux langages avec le même niveau d’exigence, alors que Bicep avait longtemps l’avantage du support « officiel » Microsoft plus poussé.
    • Terraform a intégré un framework de test natif depuis la version 1.6, réduisant la dépendance à des outils tiers comme Terratest pour valider un module avant de le publier.
    • Le provider azurerm en version 4.x a réduit le décalage historique avec les nouveaux services Azure, et le provider AzAPI comble le reste en donnant un accès direct aux API Azure Resource Manager dès leur sortie, sans attendre le mapping HCL.

    Bicep en 2026 : forces et limites

    Bicep reste l’outil natif d’Azure : pas d’état externe à gérer, syntaxe plus concise que l’ARM JSON qu’il remplace, et accès immédiat aux nouvelles fonctionnalités Azure dès leur disponibilité dans Resource Manager. Les deployment stacks permettent maintenant de gérer un ensemble de ressources comme une unité versionnée, avec un contrôle fin sur ce qui doit être supprimé (deleteAll, deleteResources ou detachAll) quand tu retires une ressource du template :

    az stack sub create \
      --name "stack-rg-prod" \
      --location "francecentral" \
      --template-file "main.bicep" \
      --deployment-resource-group "rg-prod" \
      --action-on-unmanage "deleteResources" \
      --deny-settings-mode "none"

    La limite reste son périmètre : Bicep ne pilote qu’Azure. Si ton organisation gère aussi de l’AWS, du GCP, ou des ressources SaaS (DNS, monitoring tiers…), tu devras de toute façon avoir un second outil à côté.

    Terraform en 2026 : forces et limites

    Terraform garde son atout historique : un seul outil pour orchestrer plusieurs fournisseurs, et un écosystème de providers considérable. Le framework de test natif (disponible depuis Terraform 1.6) permet d’écrire des scénarios de validation directement en HCL, sans dépendance externe :

    run "verify_resource_group_location" {
      command = plan
    
      assert {
        condition     = azurerm_resource_group.main.location == "francecentral"
        error_message = "Le resource group doit être déployé en France Central"
      }
    }

    Côté couverture Azure, le provider AzAPI comble le décalage historique avec azurerm : il expose les ressources Azure Resource Manager dès leur publication, y compris en preview, avec des fonctions pour construire et analyser les IDs de ressources directement au moment du plan. La contrepartie de Terraform reste la gestion d’un état externe : un atout pour le diff/plan avant application, mais une surface de maintenance et de sécurité (stockage, verrouillage, secrets) que Bicep n’a pas.

    Azure Verified Modules : le vrai terrain d’entente

    Les Azure Verified Modules sont sans doute le développement le plus structurant des deux dernières années sur ce sujet : des modules réutilisables, maintenus par Microsoft, conformes au Well-Architected Framework, disponibles dans les deux langages avec le même standard de qualité (tests automatisés, documentation générée, revue par les équipes Azure). Utiliser un module AVM te fait gagner du temps de conception ET réduit ton risque de config non conforme aux bonnes pratiques Azure, quel que soit le langage que tu choisis. Les équipes AVM viennent aussi de publier de la documentation sur le développement piloté par spécification avec GitHub Copilot et Spec Kit, pour accélérer la génération de solutions Azure à partir des modules — à surveiller si tu explores l’IA dans ton workflow IaC.

    C’est notamment ce qui rend la migration vers les AVM pour tes landing zones pertinente indépendamment du langage choisi : la standardisation apportée par les modules compte souvent plus que le débat Bicep vs Terraform en lui-même.

    Comment choisir sans te tromper

    Trois questions à te poser :

    • Es-tu 100 % Azure, ou multi-cloud / multi-SaaS ? Si tu es strictement Azure avec une petite équipe, Bicep te simplifie la vie (pas d’état à gérer). Dès que d’autres fournisseurs entrent en jeu, Terraform évite d’avoir deux outils à maintenir.
    • Pars-tu de zéro ou migres-tu de l’ARM JSON existant ? Bicep a un chemin de migration direct depuis l’ARM JSON (decompile automatique). Repartir de zéro en Terraform a du sens si tu anticipes une extension multi-cloud à moyen terme.
    • As-tu déjà un investissement Terraform significatif ? Si ton équipe maîtrise déjà Terraform et que ton parc de modules fonctionne bien, le coût de migration vers Bicep est rarement justifié seulement par les nouveautés listées ici. Comme le résume bien la comparaison de Technspire sur le sujet, l’outil compte moins que la discipline avec laquelle tu le maintiens : tests, revues de modules, gestion des secrets et de l’état.

    Si tu es encore sur un ancien provider azurerm, ça vaut aussi le coup de vérifier où tu en es : le guide de migration vers AzureRM 5.0 couvre les changements à anticiper avant d’aller plus loin, quel que soit le sens dans lequel tu fais évoluer ton IaC ensuite.

    FAQ

    Peut-on mixer Bicep et Terraform dans la même organisation ?

    Oui, et c’est même courant en pratique : une équipe plateforme sur Terraform pour l’infrastructure transverse (réseau, identité), et des équipes produit sur Bicep pour leurs ressources applicatives. Le risque à surveiller, c’est la duplication de logique de configuration entre les deux — les AVM aident justement à limiter ce risque en donnant un référentiel commun.

    Les deployment stacks remplacent-ils vraiment le besoin d’un état Terraform ?

    Ils comblent l’essentiel du manque pour la suppression propre des ressources, mais Bicep n’expose pas d’équivalent au terraform plan en tant que diff détaillé avant application — ce qui reste un vrai avantage de Terraform pour les changements à fort impact.

    Faut-il attendre une version encore plus mature avant de se lancer ?

    Non, les deux outils sont production-ready depuis longtemps. Le risque n’est pas dans la maturité technique, mais dans le manque de discipline (pas de revue de code IaC, pas de tests, secrets en clair) — un problème indépendant du langage choisi.

    Conclusion

    En 2026, le débat Bicep vs Terraform ressemble moins à un choix définitif qu’à une décision de contexte : Azure pur et équipe réduite pour Bicep, environnement hétérogène ou investissement existant pour Terraform. Dans les deux cas, les Azure Verified Modules sont le levier qui compte le plus pour la qualité de ton infrastructure. Commence par auditer ton parc actuel, identifie où les AVM peuvent remplacer du code IaC maison, et le choix du langage deviendra secondaire.

  • Terraform AzureRM 5.0 : ce qui change et comment migrer sans casse

    Terraform AzureRM 5.0 : ce qui change et comment migrer sans casse

    Terraform AzureRM 5.0 est disponible : pourquoi ce n’est pas une montée de version comme les autres

    Si tu gères de l’infra Azure avec Terraform, tu as sans doute déjà vu passer l’annonce : le provider hashicorp/azurerm vient de passer en version majeure 5.0, officiellement disponible en General Availability. Et contrairement aux montées de version mineures que tu appliques d’un terraform init -upgrade sans trop y réfléchir, celle-ci mérite que tu t’arrêtes cinq minutes avant de foncer.

    Pourquoi ? Parce que cette version 5.0 change des comportements par défaut qui touchent quasiment tous les projets Terraform sur Azure, même les plus simples. Si tu appliques la montée de version en production sans préparation, tu risques un terraform plan qui explose de partout — ou pire, un apply qui échoue en plein déploiement. Dans cet article, on regarde ensemble ce qui change concrètement, comment migrer sans y laisser ta soirée, et comment éviter les pièges classiques.

    Ce qui casse vraiment avec AzureRM 5.0

    HashiCorp a publié un guide de migration officiel, mais voici les points qui vont te concerner en priorité.

    1. Plus aucun Resource Provider enregistré par défaut

    C’est le changement le plus lourd de conséquences. En version 4.x, le provider enregistrait automatiquement une soixantaine de Resource Providers Azure (Microsoft.Compute, Microsoft.Network, etc.) au premier apply. Cette magie disparaît totalement en 5.0 : plus rien n’est enregistré automatiquement.

    Concrètement, si ton abonnement Azure n’a pas déjà ces providers enregistrés (ce qui est fréquent sur un abonnement neuf ou une souscription bien nettoyée), tes déploiements vont échouer avec des erreurs du type MissingSubscriptionRegistration. Deux options s’offrent à toi :

    • Lister explicitement les providers dont tu as besoin dans le bloc provider "azurerm"
    • Restaurer temporairement le comportement historique avec resource_provider_registrations = "legacy", le temps de migrer proprement
    provider "azurerm" {
      features {}
      resource_provider_registrations = "core"
      resource_providers_to_register   = [
        "Microsoft.ContainerService",
        "Microsoft.KeyVault"
      ]
    }
    

    Ça t’évite de découvrir le problème en pleine CI/CD un vendredi après-midi.

    2. La validation renforcée change de camp

    Le bloc enhanced_validation déménage à l’intérieur de features, et surtout, la validation des régions et des providers passe à désactivée par défaut. Résultat : les erreurs qui remontaient auparavant pendant le plan (une région mal orthographiée, par exemple) ne se déclenchent maintenant qu’au moment de l’apply. Si tu veux garder ce filet de sécurité en amont, réactive-le explicitement :

    provider "azurerm" {
      features {}
      enhanced_validation {
        locations = true
      }
    }
    

    3. Validation Preflight, mais seulement pour six ressources

    Nouveauté intéressante : le provider peut désormais valider certaines charges utiles directement contre l’API Preflight d’Azure, avant même de tenter le déploiement. Le hic, c’est que ça ne couvre pour l’instant que six types de ressources : App Service Environment v3, Service Plan, Grafana, Redis, NGINX et Event Grid. Pour tout le reste, cette protection ne s’applique pas — ne compte pas dessus comme filet universel.

    4. Les ressources App Service et Function App historiques disparaissent

    Si ton code utilise encore azurerm_app_service ou azurerm_function_app, il va falloir migrer vers les variantes typées par OS : azurerm_linux_web_app, azurerm_windows_web_app, azurerm_linux_function_app, azurerm_windows_function_app. Ce n’est pas qu’un renommage : ça implique une migration d’état Terraform (terraform state mv ou import) puisque le schéma des ressources change.

    5. Des changements de schéma plus discrets, mais tout aussi cassants

    En plus des gros titres, attends-toi à des surprises plus subtiles : des propriétés renommées avec parfois une inversion de polarité (par exemple disable_automatic_rollback devient automatic_rollback_enabled — attention au sens inverse du booléen), des attributs autrefois optionnels devenus obligatoires, des types qui passent de liste à set, et des blocs imbriqués promus en ressources autonomes. Ce sont typiquement les erreurs qui ne sautent pas aux yeux en relisant le changelog en diagonale.

    Comment migrer sans casser ta prod

    Voici la méthode que je te recommande, plutôt que de foncer tête baissée :

    • Épingle la version avant de migrer : version = "= 4.x.x" le temps de préparer le terrain, puis bascule sur = 5.0.0 de façon contrôlée plutôt que d’utiliser une contrainte ouverte comme ~> 5.0 dès le départ.
    • Teste sur une souscription non-production. Si tu n’en as pas, crée un abonnement Azure dédié aux tests d’infra — ça coûte moins cher qu’un incident en prod.
    • Lance un terraform plan complet et lis-le en entier, pas juste le résumé. C’est là que tu repères les changements de schéma silencieux.
    • Traite les migrations d’état séparément des autres changements, pour isoler les risques (App Service/Function App notamment).
    • Automatise la vérification dans ta pipeline CI/CD : un job qui bloque le merge si le plan détecte un destroy non attendu te sauve la mise plus d’une fois.

    Et si tu n’es pas encore prêt à migrer ?

    Rien ne t’oblige à sauter sur la 5.0 le jour de sa sortie. Tu peux tout à fait rester sur la branche 4.x le temps de planifier la migration — HashiCorp continue de publier des correctifs sur les anciennes versions majeures pendant une période de transition. Consulte le registre officiel du provider pour suivre les releases et leur statut de support.

    Si c’est l’outil lui-même que tu remets en question plutôt que la version du provider, regarde mon comparatif OpenTofu vs Terraform.

    Ce qui compte, c’est que la migration soit un choix planifié et testé, pas une surprise découverte parce qu’une contrainte de version trop permissive a tiré la 5.0 automatiquement dans ta CI.

    Automatise la détection des breaking changes avant qu’ils ne te surprennent

    Une bonne pratique que je te recommande, au-delà de cette migration précise : intègre un contrôle statique dans ta pipeline CI/CD pour repérer les changements risqués avant même d’arriver au plan. Des outils comme tflint ou checkov peuvent te signaler l’usage de ressources dépréciées ou de mauvaises pratiques directement dans ta merge request, avant que ça n’atteigne l’environnement de test.

    # Exemple minimal d'étape CI
    - name: Lint Terraform
      run: |
        tflint --init
        tflint
    - name: Terraform plan
      run: terraform plan -out=tfplan
    

    Combine ça avec une revue systématique du plan par un humain avant tout apply en production, même si ta pipeline est largement automatisée. Les changements de schéma silencieux comme ceux qu’AzureRM 5.0 introduit sont justement le genre de choses qu’un œil attentif repère, mais qu’un pipeline purement automatisé peut laisser passer si tu n’as pas configuré les bons garde-fous.

    FAQ

    Dois-je migrer immédiatement vers AzureRM 5.0 ?

    Non, pas dans l’urgence. Prends le temps de tester en environnement isolé. Fixe une version explicite dans tes fichiers Terraform pour éviter qu’une mise à jour automatique te bascule en 5.0 sans préparation.

    Le comportement « legacy » d’enregistrement des providers va-t-il disparaître ?

    HashiCorp le présente comme une option de transition. Ne construis pas ta stratégie long terme dessus : c’est fait pour t’aider à migrer en douceur, pas pour rester en place indéfiniment.

    Comment je repère les ressources dépréciées dans mon code existant ?

    Le guide de migration officiel liste les ressources et attributs concernés. Un passage par terraform plan avec la 5.0 activée en environnement de test te montrera aussi les erreurs de schéma directement.

    Est-ce que ça concerne aussi Bicep ou seulement Terraform ?

    Uniquement Terraform et le provider AzureRM. Bicep, qui parle directement à l’API Azure Resource Manager, n’est pas concerné par ces changements côté provider tiers.

    Si tu hésites encore entre les deux outils, j’ai comparé Terraform et Bicep pour Azure.

    Que faire si je découvre un breaking change non documenté ?

    Ouvre une issue sur le dépôt GitHub du provider. La communauté et l’équipe HashiCorp sont réactives, et ça évite à d’autres admins de tomber dans le même piège.

    En résumé

    AzureRM 5.0 apporte de vraies améliorations — moins de magie cachée, plus de contrôle explicite sur ce que Terraform fait dans ton abonnement Azure. Mais ça se paie par une migration qui demande de la méthode. Prends le temps de tester, épingle tes versions, et lis vraiment tes plan avant de les appliquer. Ton futur toi (et ton équipe d’astreinte) t’en remerciera.

    Tu as déjà migré et rencontré un cas particulier pas couvert ici ? Partage-le, ça aide toute la communauté Azure/Terraform à anticiper.