Sägetstrasse 18, 3123 Belp, Switzerland +41 79 173 36 84 info@ict.technology

    Terraform @ Scale - Partie 7 : Bonnes pratiques pour le versionnage des modules

    "Versionnage ? Oh, je prends toujours la dernière version - qu’est-ce qui pourrait bien mal tourner ?"

    C’est précisément ce genre d’attitude qui explique pourquoi certains ingénieurs sont réveillés à 3 heures du matin par un appel d’urgence. Et pourquoi, le lendemain matin, tout le monde regarde ses chaussures pendant le Daily Stand-up.

    Avant que cela ne vous arrive aussi, parlons-en brièvement dans le dernier volet de notre série « Terraform @ Scale ».

    Après avoir abordé dans les précédents volets de cette série les dépendances, le Blast-Radius et les tests, nous allons aujourd’hui traiter d’un sujet souvent sous-estimé : le versionnage professionnel des modules Terraform. Car un module sans versionnage rigoureux, c’est comme une voiture sans contrôle technique : elle peut rouler un certain temps, mais tôt ou tard, les ennuis arrivent.

    Pourquoi le versionnage des modules est essentiel

    Imaginez : un module réseau central est utilisé par 42 projets différents. Le développeur d’origine a quitté l’équipe, sa documentation se résume à « voir le code », et il faut maintenant modifier d’urgence le module. Sans versionnage clair, vous ignorez :

    • Quels projets utilisent quelle version du module
    • Si une mise à jour entraînera des Breaking Changes pour les déploiements existants
    • Comment effectuer un rollback en cas de problème
    • Quand et pourquoi le module a été modifié pour la dernière fois

    Le résultat ? La fameuse alerte de 3 heures du matin, parce que plus personne ne sait où se trouvent les dépendances. Et ensuite commence la grande séance de devinettes, pendant que l’infrastructure brûle.

    Le versionnage professionnel des modules n’est pas un « Nice-to-Have » pour perfectionnistes. C’est la base qui garantit que votre Infrastructure-as-Code reste maintenable, même avec plus de 100 projets, sans devoir entreprendre des fouilles archéologiques pour comprendre ce qui a été fait, quand et pourquoi.

    Semantic Versioning - La lingua franca du versionnage

    Le Semantic Versioning (SemVer) est le standard de facto pour le versionnage logiciel, et donc le seul choix sensé pour les modules Terraform. Le schéma est simple : MAJOR.MINOR.PATCH (par ex. v1.3.7).

    Les trois composants en détail

    Version MAJOR (1.x.x) - Le grand coup de massue :

    Augmentée en cas de Breaking Changes, c’est-à-dire de modifications qui cassent le code existant. Exemples :

    • Une variable obligatoire est renommée ou supprimée
    • Un output est supprimé alors que d’autres modules y dépendent
    • La structure de ressource change, nécessitant un terraform state mv
    • Les exigences du Provider changent de manière incompatible (ex. passage du Provider AWS 4.x à 5.x)

    Règle empirique : Si les utilisateurs du module DOIVENT adapter leur configuration Terraform, c’est une mise à jour majeure.

    Version MINOR (x.1.x) - L’extension bienveillante :

    Augmentée lors de l’ajout de nouvelles fonctionnalités rétrocompatibles. Exemples :

    • Nouvelles variables optionnelles avec valeurs par défaut cohérentes
    • Outputs supplémentaires que personne n’avait encore remarqués comme manquants
    • Nouveaux sous-modules ou ressources optionnels
    • Améliorations de performance sans changement fonctionnel

    Règle empirique : Le code existant fonctionne toujours, mais de nouvelles possibilités apparaissent. La mise à jour est optionnelle, mais recommandée.

    Version PATCH (x.x.1) - Le correctif :

    Augmentée lors de corrections de bugs n’affectant pas la logique fonctionnelle. Exemples :

    • Correction de fautes de frappe dans les descriptions d’outputs ou de variables
    • Correction de race conditions ou de problèmes de synchronisation
    • Mises à jour de documentation
    • Correction de valeurs par défaut manifestement erronées

    Règle empirique : Pur correctif. Les mises à jour doivent toujours être sûres.

    Pre-Release et Build-Metadata

    SemVer permet d’ajouter des indications supplémentaires pour les versions bêta ou les métadonnées de build :


    v1.2.3-beta.1       # Version bêta 
    v1.2.3-rc.2         # Release Candidate
    v1.2.3+build.42     # Métadonnées de build (ignorées lors des comparaisons de version)
    v2.0.0-alpha.1      # Version alpha d’une mise à jour majeure

    Ces versions préliminaires sont destinées au développement et aux tests. Elles n’ont rien à faire en production - même si certaines équipes pensent le contraire et en paient ensuite le prix.

    Scénarios de mise à jour de modules et leurs pièges

    La théorie est belle, mais la pratique est, comme souvent, plus complexe. Voyons ce qui se passe lorsque vous essayez de mettre à jour un module de la version v1.0.0 vers différentes versions plus récentes.

    La mise à jour douce (v1.0.0 → v1.0.1)

    Cela devrait être l’exercice le plus simple. Un correctif de bug, pas de Breaking Changes, rien de dramatique. En théorie, il suffit d’exécuter un terraform init -upgrade et c’est fini.

    En pratique, vous pouvez trébucher sur :

    • Provider-Lock-Files : votre fichier .terraform.lock.hcl contient peut-être des empreintes verrouillées incompatibles avec le correctif
    • State-Drift : le correctif résout une erreur déjà inscrite dans le State - Terraform veut donc modifier des ressources
    • Dépendances descendantes : d’autres modules utilisant le vôtre ont leurs propres fichiers de verrouillage

    Bonne pratique : même pour les mises à jour correctives, exécutez un plan dans un environnement de test. Pas par paranoïa, mais par expérience.

    La mise à jour mineure bienveillante (v1.0.0 → v1.1.0)

    Nouvelles fonctionnalités, rétrocompatibles. Cela semble parfait. Mais « rétrocompatible » ne veut pas dire « sans effet ». Les nouvelles variables optionnelles ont des valeurs par défaut, et ces valeurs par défaut s’appliquent, que vous le vouliez ou non.

    Scénario d’exemple :


    # v1.0.0 - Original Version
    resource "oci_core_vcn" "this" {
      compartment_id = var.compartment_id
      cidr_block     = var.cidr_block
      display_name   = var.display_name
    }
    
    # v1.1.0 - New optional Features
    resource "oci_core_vcn" "this" {
      compartment_id = var.compartment_id
      cidr_block     = var.cidr_block
      display_name   = var.display_name
      
      # NEW: Optional DNS Configuration
      dns_label = var.dns_label # Default: null
      
      # NEW: Optional IPv6 Support  
      is_ipv6enabled = var.enable_ipv6 # Default: false
    }

    Que se passe-t-il lors de la mise à jour ? Terraform détecte de nouveaux arguments dans la ressource. Même si les valeurs par défaut sont « null » ou « false », Terraform doit évaluer s’il y a un changement. Selon le Provider et la ressource, cela peut conduire à une mise à jour in-place ou même à un remplacement.

    Spécificité du Provider : avec certains Providers, un nouveau « false » par défaut peut tout de même déclencher un changement dans le plan si le Provider traite l’état « unset » différemment de « false ». Cela concerne surtout les attributs booléens ajoutés après coup à des ressources existantes.

    Bonne pratique : testez soigneusement les mises à jour mineures dans les environnements DEV. Vérifiez la sortie du plan pour repérer des changements inattendus. Et oui, cela signifie réellement lire le plan, pas seulement le survoler.

    La mise à jour majeure redoutée (v1.5.0 → v2.0.0)

    Ici, les choses deviennent sérieuses. Les Breaking Changes signifient : votre code existant VA casser. La seule question est où, et à quel point.

    Scénarios typiques lors de mises à jour majeures :

    • Variable renommée : subnet_ids s’appelle désormais subnet_id_list
    • Structure d’output modifiée : ce qui était une liste est maintenant une map
    • Adresses de ressources déplacées : migration du State nécessaire
    • Exigences Provider augmentées : OCI Provider 5.x → 6.x

    Le symbole avec le point d’interrogation rouge dans le graphique ci-dessus n’est pas là par hasard. Lors de mises à jour majeures, il se peut qu’une mise à niveau directe de v1.5.0 à v2.0.0 ne fonctionne tout simplement pas. La raison : trop de Breaking Changes d’un coup.

    Bonne pratique : lisez les Release Notes. Toutes. En entier. Créez une checklist de migration. Testez dans des environnements isolés. Prévoyez des stratégies de rollback. Et attendez-vous à l’inattendu.

    Version Pinning - L’art du chaos maîtrisé

    Passons à la pratique. Comment verrouiller les modules sur des versions spécifiques ? Terraform propose plusieurs mécanismes selon la source du module.

    Modules basés sur Git avec paramètre ref

    Pour les modules dans des dépôts Git, le paramètre ?ref= est la méthode standard :


    # Via Git-Tag (minimum for production environments)
    module "vpc" {
      source = "git::https://github.com/your-org/terraform-modules.git//vpc?ref=v1.2.3"
      
      compartment_id = var.compartment_id
      cidr_block     = "10.0.0.0/16"
    }
    
    # Via Branch (only fpr development!)
    module "vpc_dev" {
      source = "git::https://github.com/your-org/terraform-modules.git//vpc?ref=develop"
      
      compartment_id = var.dev_compartment_id
      cidr_block     = "172.16.0.0/16"
    }
    
    # Via Commit Hash (for maximum security, recommended)
    module "vpc_immutable" {
      source = "git::https://github.com/your-org/terraform-modules.git//vpc?ref=a1b2c3d4"
      
      compartment_id = var.compartment_id
      cidr_block     = "192.168.0.0/16"
    }

    Important : le ?ref= vient APRÈS le chemin du module (//vpc), pas avant. Cette erreur est étonnamment fréquente et conduit à des messages d’erreur obscurs.

    Remarque sur les Commit Hashes : lorsque vous utilisez des Commit Hashes, utilisez toujours le hash complet. Les hashes abrégés à 7 caractères peuvent être impossibles à résoudre selon la configuration du serveur Git et provoquer des erreurs lors du terraform init.

    Terraform Registry avec des contraintes de version

    Pour les modules issus de Terraform Registries publiques ou privées, utilisez le paramètre version :


    # Exact Version (maximum pinning)
    module "vpc" {
      source  = "oracle-terraform-modules/vcn/oci"
      version = "3.5.4"
      
      compartment_id = var.compartment_id
      vcn_cidr       = "10.0.0.0/16"
    }
    
    # Pessimistic Constraint Operator (recommended)
    module "vpc_safe" {
      source  = "oracle-terraform-modules/vcn/oci"
      version = "~> 3.5.0"  # Allows 3.5.x, but not 3.6.0
      
      compartment_id = var.compartment_id
      vcn_cidr       = "10.0.0.0/16"
    }
    
    # Range Constraints (allows more flexibility)
    module "vpc_range" {
      source  = "oracle-terraform-modules/vcn/oci"
      version = ">= 3.5.0, < 4.0.0"  # All 3.x Versions, starting with 3.5.0
      
      compartment_id = var.compartment_id
      vcn_cidr       = "10.0.0.0/16"
    }

    Version Constraint Operators - Les petites lignes

    Terraform prend en charge différents opérateurs pour les contraintes de version :

    • = ou aucune indication : version exacte (par ex. = 1.2.3 ou 1.2.3)
    • != : toutes les versions sauf celle-ci (par ex. != 1.2.3)
    • >, >=, <, <= : opérateurs de comparaison (par ex. >= 1.2.0)
    • ~> : Pessimistic Constraint - n’autorise que les incréments du composant de version le plus à droite indiqué (par ex. ~> 1.2.0 autorise >= 1.2.0 et < 1.3.0)

    L’opérateur ~> mérite une attention particulière. Il n’autorise que les incréments du composant le plus à droite indiqué :


    ~> 1.2     # Allows >= 1.2.0 and < 2.0.0 (all minor- and patch versions in Major 1)
    ~> 1.2.0   # Allows >= 1.2.0 and < 1.3.0 (all patches in minor 1.2)
    ~> 1.2.3   # Allows >= 1.2.3 und < 1.3.0 (all patches starting with 1.2.3 in minor 1.2)

    Pour les environnements de production, nous recommandons : versions exactes ou ~> avec spécification du patch (par ex. ~> 3.5.0), afin de n’autoriser que les versions correctives au sein d’une même version mineure. Si vous souhaitez aussi autoriser automatiquement les mises à jour mineures, utilisez ~> 3.5 - mais cela autorise toutes les versions jusqu’à < 4.0.0. Tout le reste conduira tôt ou tard à des surprises inattendues.

    Verrouillage des versions dans les grands environnements - La dure réalité

    Dans de petits setups, vous pouvez verrouiller manuellement chaque module sur une version spécifique. Mais cela engendre du micro-management et ne passe pas à l’échelle.

    Avec 5 projets, cela reste gérable.

    Avec 50 projets, cela devient laborieux.

    Avec 500 projets, c’est impossible.

    Le minimum de verrouillage via URL Git

    Avec Terraform Open Source, pour les modules basés sur Git, il ne vous reste que le paramètre ?ref=. C’est la solution minimale. Elle fonctionne, mais vous devez manuellement :

    • Ajouter un ?ref= à chaque appel de module
    • Lors des mises à jour, retrouver et modifier tous les emplacements concernés dans le code
    • Espérer que personne n’oublie d’ajouter le ?ref=

    Pour des environnements sérieux, ce n’est pas durable. C’est comme enfoncer des vis dans le mur avec un marteau - techniquement possible, tolérable dans de rares exceptions, mais l’appliquer en général serait idiot. À partir d’une certaine taille de base de code IaC, il faut des solutions plus professionnelles.

    La solution Registry avec des contraintes de version

    Mieux, mais pas parfait non plus : une Terraform Registry privée avec des contraintes de version. Vous pouvez contrôler finement quelles versions sont autorisées :


    # In versions.tf
    terraform {
      required_version = ">= 1.10.0"
      
      required_providers {
        oci = {
          source  = "oracle/oci"
          version = "~> 6.0"
        }
      }
    }
    
    # In main.tf
    module "vcn" {
      source  = "your-company.com/modules/oci-vcn"
      version = "~> 2.1.0"  # Allows Patches, but not minor Upgrades
      
      compartment_id = var.compartment_id
      cidr_block     = "10.0.0.0/16"
    }

    Le problème : vous devez malgré tout parcourir tous les repositories et mettre à jour les contraintes version si vous voulez effectuer une mise à jour avec Breaking Changes. Avec plus de 100 repositories, c’est un job à plein temps.

    Contraintes de version pour les modules - L’approche Enterprise

    Dans Terraform Enterprise ou Terraform Cloud, vous pouvez définir des contraintes de version pour les modules au niveau des Workspaces, voire globalement. C’est la solution professionnelle pour les grands environnements :


    # Sentinel policy for module versioning
    import "tfconfig/v2" as tfconfig
    
    # Define allowed versions per module
    allowed_module_versions = {
      "oracle-terraform-modules/vcn/oci": {
        "min_version": "3.5.0",
        "max_version": "3.9.9",
      },
      "your-company.com/modules/oci-compute": {
        "min_version": "2.0.0",
        "max_version": "2.9.9",
      },
    }
    
    # Verify all modul calles
    import "versions"
    
    mandatory_version_constraint = rule {
      all tfconfig.module_calls as name, module {
    
        # Only for registry sources which we want to manage explicitely
        has_key(allowed_module_versions, module.source) implies (
          module.version is not null and
          func() {
            v = allowed_module_versions[module.source]
            c = versions.constraint(">= " + v.min_version + ", <= " + v.max_version)
            versions.matches(c, module.version)
          }()
        )
      }
    }

    Avec Sentinel, vous pouvez contrôler de manière centralisée quelles versions de modules sont autorisées dans quels Workspaces. Une mise à niveau vers une nouvelle Major Release est alors déployée via une modification de la Sentinel Policy, et non par des changements dans chaque repository.

    C’est du Version Management de niveau Enterprise. Cela coûte en conséquence en budget et en effort de mise en place, mais cela passe réellement à l’échelle sur des centaines de projets.

    Tests de mise à niveau de modules avec le Terraform Testing Framework

    Vous avez mis à jour un module. Vous devez maintenant tester si tout fonctionne encore. Les tests manuels sont pour les amateurs. Les professionnels automatisent.

    Le Terraform Testing Framework (à partir de Terraform 1.6, considérablement amélioré en 1.10+) fournit exactement les bons outils. Voici un exemple pratique pour des tests de mise à niveau de modules :

    Avantage supplémentaire : le Testing Framework peut aussi servir de garde-fou contre des lots trop volumineux - via des tests qui limitent le nombre de modifications de ressources planifiées. Cela atténue indirectement les problèmes de limites d’API que nous avons traités en détail dans les parties précédentes de cette série.

    Scénario de test : mise à niveau du module VCN de v2.5.0 à v3.0.0


    # tests/upgrade_v2_to_v3.tftest.hcl
    variables {
      compartment_id = "ocid1.compartment.oc1..example"
      vcn_cidr       = "10.0.0.0/16"
      vcn_name       = "test-upgrade-vcn"
    }
    
    # Test 1: Existing v2.5.0 funktionality
    run "test_v2_baseline" {
      command = plan
      
      module {
        source  = "oracle-terraform-modules/vcn/oci"
        version = "2.5.0"
      }
      
      assert {
        condition     = length(output.vcn_id.value) > 0
        error_message = "VCN ID should be generated in v2.5.0"
      }
      
      assert {
        condition     = output.vcn_cidr_block.value == var.vcn_cidr
        error_message = "CIDR block mismatch in v2.5.0"
      }
    }
    
    # Test 2: v3.0.0 breaking changes
    run "test_v3_migration" {
      command = plan
      
      module {
        source  = "oracle-terraform-modules/vcn/oci"
        version = "3.0.0"
      }
      
      # v3.0.0 renamed 'vcn_name' to 'display_name'
      variables {
        display_name = var.vcn_name  # Neuer Parameter-Name
      }
      
      assert {
        condition     = length(output.vcn_id.value) > 0
        error_message = "VCN ID should still be generated in v3.0.0"
      }
      
      assert {
        condition     = output.vcn_display_name.value == var.vcn_name
        error_message = "Display name not correctly migrated to v3.0.0"
      }
    }
    
    # Test 3: Backwards Compatibility Check
    run "test_output_compatibility" {
      command = plan
      
      module {
        source  = "oracle-terraform-modules/vcn/oci"
        version = "3.0.0"
      }
      
      variables {
        display_name = var.vcn_name
      }
      
      # Check if critical outputs still exist
      assert {
        condition = (
          can(output.vcn_id.value) &&
          can(output.vcn_cidr_block.value) &&
          can(output.default_route_table_id.value)
        )
        error_message = "Critical outputs missing in v3.0.0 - breaking downstream dependencies!"
      }
    }

    Ces tests s’exécutent avec terraform test et échouent lorsqu’une mise à niveau introduit des Breaking Changes non documentées ou non traitées.

    Intégration avec CI/CD

    Les tests ne valent que par leur automatisation. Voici un exemple GitLab CI/CD :


    # .gitlab-ci.yml
    stages:
      - test
      - plan
      - apply
    
    terraform_test:
      stage: test
      image: hashicorp/terraform:1.10
      script:
        - terraform init
        - terraform test -verbose
      only:
        - merge_requests
        - main
    
    terraform_plan:
      stage: plan
      image: hashicorp/terraform:1.10
      script:
        - terraform init
        - terraform plan -out=tfplan
      dependencies:
        - terraform_test
      only:
        - main
      artifacts:
        paths:
          - tfplan
    
    terraform_apply:
      stage: apply
      image: hashicorp/terraform:1.10
      script:
        - terraform init
        - terraform apply tfplan
      dependencies:
        - terraform_plan
      only:
        - main
      when: manual

    Pas de plan sans tests réussis. Pas d’apply sans plan réussi. C’est la pipeline que vous souhaitez.

    Conseil complémentaire : en plus des tests, vous devriez mettre en place des analyses automatiques des plans pour détecter les changements destructifs (delete/destroy), comme nous l’avons déjà abordé dans les parties précédentes de cette série. Ces systèmes d’alerte précoce complètent les garde-fous des tests et interceptent les problèmes de Blast-Radius avant qu’ils n’atteignent la Production.

    Sentinel Policies pour l’application des versions

    Les tests, c’est bien. Les policies, c’est mieux. Car les tests peuvent être contournés si l’on veut vraiment (ou si l’on est paresseux). Les Sentinel Policies dans Terraform Enterprise, elles, ne peuvent pas être contournées - sauf si vous êtes administrateur, et là, c’est un tout autre problème.

    Policy : imposer le versionnage des modules


    import "tfconfig/v2" as tfconfig
    import "strings"
    
    # Helper function: is the source a VCS (git)?
    is_vcs = func(src) {
      strings.has_prefix(src, "git::") or strings.contains(src, "://")
    }
    
    # Helper function: Extract ref parameter from URL
    ref_of = func(src) {
      idx = strings.index_of(src, "?ref=")
      idx >= 0 ? strings.substring(src, idx+5, -1) : ""
    }
    
    # Policy: All non-local modules MUST be versioned
    mandatory_versioning = rule {
      all tfconfig.module_calls as name, module {
        # Local modules (./ oder ../) are exempt
        not (strings.has_prefix(module.source, "./") or 
             strings.has_prefix(module.source, "../")) implies (
          # For VCS sources: ?ref= must exist
          is_vcs(module.source) implies length(ref_of(module.source)) > 0
          and
          # For registry sources: version must be set
          not is_vcs(module.source) implies module.version is not null
        )
      }
    }
    
    # Main policy
    main = rule {
      mandatory_versioning
    }

    Cette policy rejette tout terraform plan ou apply dans lequel un module n’est pas correctement versionné. Aucune exception. Aucune indulgence.

    Policy : interdire les versions connues comme défectueuses


    import "tfconfig/v2" as tfconfig
    
    # Deny-list for modules with known bugs
    forbidden_module_versions = {
      "oracle-terraform-modules/vcn/oci": ["3.2.0", "3.2.1"],  # Bug in DHCP-Options
      "your-company.com/modules/compute": ["1.5.0"],          # Security Issue
    }
    
    # Policy: Disallow known faulty versions
    deny_forbidden_versions = rule {
      all tfconfig.module_calls as name, module {
        has_key(forbidden_module_versions, module.source) implies (
          module.version not in forbidden_module_versions[module.source]
        )
      }
    }
    
    
    main = rule {
      deny_forbidden_versions
    }

    Vous disposez désormais d’un mécanisme permettant de bloquer globalement les versions critiques de modules. Si la version 3.2.0 du module VCN contient un bug majeur, vous la bloquez dans la policy. C’est tout. Plus personne ne pourra l’utiliser, même pas « par accident ».

    Workflows pratiques pour les mises à jour de modules

    La théorie, c’est bien. La pratique, c’est mieux. Voici des workflows éprouvés pour différents scénarios de mise à jour.

    Workflow 1 : mise à jour correctrice (par ex. v2.3.1 → v2.3.2)

    1. Communication : annonce dans le chat d’équipe, même s’il ne s’agit « que » d’un patch
    2. Test en DEV : mise à jour dans l’environnement de développement, terraform init -upgrade, vérification du plan
    3. Tests automatisés : exécution de terraform test
    4. Déploiement en Staging : déploiement en Staging, suivi pendant 24 h
    5. Déploiement en production : déploiement en production pendant les heures ouvrées (pas le vendredi à 16 h)
    6. Documentation : mise à jour du CHANGELOG et de la documentation Confluence/Wiki

    Durée : 1 à 3 jours, selon la taille de l’environnement

    Remarque : les durées indiquées sont basées sur l’expérience et peuvent varier considérablement en fonction des exigences de conformité (SOX, ISO, RGPD) et des processus de gestion du changement.

    Workflow 2 : mise à jour mineure (par ex. v2.3.2 → v2.4.0)

    1. Analyse des Release Notes : lecture complète de toutes les nouvelles fonctionnalités et modifications
    2. Analyse d’impact : quels nouveaux defaults sont activés ? Y a-t-il des effets de bord inattendus ?
    3. Plan de test : création de scénarios de test documentés pour les nouvelles fonctionnalités
    4. Tests en DEV : tests approfondis dans l’environnement de développement (au moins 1 semaine)
    5. Canary Deployment : déploiement sur un petit sous-ensemble de production
    6. Phase de monitoring : 1 semaine de suivi du Canary Deployment
    7. Déploiement complet : déploiement progressif sur plusieurs jours/semaines
    8. Postmortem Review : documentation des leçons apprises

    Durée : 2 à 4 semaines, selon l’évaluation du risque

    Workflow 3 : mise à jour majeure (par ex. v2.4.0 → v3.0.0)

    1. Inventaire des Breaking Changes : établir la liste complète de toutes les modifications incompatibles
    2. Guide de migration : créer un guide détaillé pour chaque Breaking Change
    3. Analyse des dépendances : identifier les modules en aval concernés
    4. Environnement de test : mise en place d’un environnement dédié au test de migration
    5. Test de migration du State : Terraform State Surgery si nécessaire
    6. Stratégie de rollback : plan documenté pour le pire scénario
    7. Migration en DEV : migration complète en développement avec tests
    8. Migration en Staging : migration en Staging avec 2 semaines de suivi
    9. Réunion Go/No-Go : décision formelle basée sur les résultats des tests
    10. Migration en production : fenêtre de maintenance planifiée, mobilisation complète de l’équipe
    11. Monitoring post-migration : suivi intensif pendant 2 semaines
    12. Mise à jour de la documentation : actualisation de tous les documents à la nouvelle version

    Durée : 1 à 3 mois, selon la complexité et la taille

    Checklist : versionnage professionnel des modules

    ✅ Fondamentaux

    [ ] Le Semantic Versioning est appliqué de manière cohérente à tous les modules
    [ ] Des Git-Tags sont créés pour chaque version (pas seulement pour les Major-Releases)
    [ ] Le fichier CHANGELOG.md est mis à jour à chaque release
    [ ] Les Release Notes sont claires et complètes (pas seulement « minor fixes »)
    [ ] Les Breaking Changes sont clairement signalés et documentés

    ✅ Version Pinning

    [ ] Tous les appels de modules utilisent un version-pinning explicite (pas de « latest »)
    [ ] Les modules Git utilisent ?ref= avec des tags concrets, pas des branches
    [ ] Les modules de Registry utilisent des contraintes de version (idéalement ~>)
    [ ] Les environnements de développement/test peuvent être plus souples que la production
    [ ] Les fichiers de verrouillage (.terraform.lock.hcl) sont versionnés dans Git

    ✅ Tests et validation

    [ ] Le Terraform Testing Framework est implémenté pour tous les modules critiques
    [ ] Des tests de mise à niveau existent pour les mises à jour majeures et mineures
    [ ] Les tests s’exécutent automatiquement dans la pipeline CI/CD
    [ ] La compatibilité ascendante est testée avant chaque release
    [ ] Des tests de régression pour les bugs connus sont disponibles

    ✅ Gouvernance

    [ ] Les Sentinel Policies imposent le versionnage des modules (Terraform Enterprise)
    [ ] Une liste d’exclusion pour les versions défectueuses de modules est implémentée
    [ ] Le processus de mise à jour des versions est documenté et appliqué
    [ ] Les modifications de modules passent par un processus de revue
    [ ] Les mises à jour majeures nécessitent une réunion Go/No-Go formelle

    ✅ Documentation

    [ ] Le README.md explique la stratégie de versionnage du module
    [ ] Le CHANGELOG.md est maintenu et suit le format Keep-a-Changelog
    [ ] Des guides de migration existent pour toutes les mises à jour majeures
    [ ] Les problèmes connus (Known Issues) sont documentés
    [ ] Les avis de dépréciation sont communiqués au moins 2 versions mineures à l’avance

    ✅ Monitoring et gestion des incidents

    [ ] Les versions des modules déployés sont traçables (logs, tags)
    [ ] Des alertes sont actives en cas de mise à jour de module inattendue
    [ ] Les procédures de rollback sont documentées et testées
    [ ] Un playbook Incident Response pour les problèmes de modules existe
    [ ] Un processus postmortem est en place après les mises à jour échouées

    Pensées finales

    Le versionnage des modules n’est pas un sujet « glamour ». Ce n’est pas le thème des conférences. Il n’y a ni belles animations, ni démos impressionnantes. Mais c’est la différence entre une infrastructure encore maintenable après trois ans et un chaos illisible que plus personne n’ose toucher.

    Si vous ne retenez qu’une chose de cet article, que ce soit celle-ci : investissez maintenant dans un versionnage propre, ou payez plus tard le prix fort sous forme d’incidents, de rollbacks et d’astreintes du week-end.

    Les alertes de 3 heures du matin ne disparaîtront peut-être pas complètement. Mais elles deviendront beaucoup plus rares. Et c’est déjà ça.

    Car la seule version utile, c’est celle que vous pouvez contrôler.