Aller au contenu
Infrastructure as Code medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Diagnostiquer le state Terraform

14 min de lecture

logo terraform

Quand quelqu’un modifie manuellement une ressource — supprime un réseau via la console, change un paramètre en SSH — le state Terraform ne le sait pas. L’écart entre ce que le state décrit et ce qui existe réellement s’appelle le drift. terraform plan le détecte, terraform apply -refresh-only met le state à jour, et terraform import rattache une ressource existante que Terraform ne connaît pas encore. Ces trois mécanismes forment votre boîte à outils de diagnostic.

Prérequis : connaître la structure du state et savoir utiliser terraform state list et terraform state show.

  • Détecter le drift avec terraform plan
  • Mettre à jour le state sans modifier l’infrastructure avec terraform apply -refresh-only
  • Importer une ressource existante dans le state avec terraform import
  • Utiliser le bloc import comme alternative déclarative (Terraform >= 1.5)
  • Automatiser la détection de drift avec -detailed-exitcode

Le drift (dérive) apparaît quand l’infrastructure réelle ne correspond plus à ce que le state décrit. Les causes les plus fréquentes sont :

CauseExemple concret
Modification manuelleQuelqu’un désactive l’autostart d’un réseau via la console
Action d’un autre outilUn script Ansible modifie une configuration
Suppression externeUn collègue supprime une VM directement
Expiration automatiqueUn certificat ou une ressource temporaire expire

Le drift n’est pas une erreur en soi — c’est une désynchronisation entre le state et la réalité. Le problème survient si vous ne le détectez pas : le prochain apply peut produire des résultats inattendus.

terraform plan compare systématiquement le state avec l’infrastructure réelle avant de calculer les changements. Si une ressource a été modifiée en dehors de Terraform, le plan le signale.

Imaginons qu’un collègue désactive l’autostart d’un réseau directement en ligne de commande :

Fenêtre de terminal
terraform plan
libvirt_network.net: Refreshing state... [id=a12f1d21-0a1e-4af2-9b0b-2c7c59d043df]
Terraform used the selected providers to generate the following execution plan.
# libvirt_network.net will be updated in-place
~ resource "libvirt_network" "net" {
~ autostart = false -> true
id = "a12f1d21-0a1e-4af2-9b0b-2c7c59d043df"
name = "mon-reseau"
}
Plan: 0 to add, 1 to change, 0 to destroy.

Le plan montre autostart = false -> true : la valeur réelle (false) diffère de la valeur déclarée dans le code (true). Terraform propose de corriger le drift en remettant la valeur du code.

Quand terraform plan détecte un drift, vous avez deux choix :

StratégieCommandeQuand l’utiliser
Corriger le driftterraform applyLa modification manuelle était une erreur — vous voulez remettre l’infrastructure conforme au code
Accepter le driftterraform apply -refresh-onlyLa modification manuelle était intentionnelle — vous voulez mettre le state à jour pour refléter la réalité

N’utilisez plus terraform refresh dans les guides récents ou vos scripts : préférez terraform apply -refresh-only, qui montre les écarts détectés et demande une confirmation avant d’écrire dans le state.

terraform apply -refresh-only lit l’état réel de chaque ressource et met à jour le state sans modifier l’infrastructure. C’est l’inverse d’un apply classique : au lieu de rendre l’infrastructure conforme au code, il rend le state conforme à la réalité.

Fenêtre de terminal
terraform apply -refresh-only
libvirt_network.net: Refreshing state... [id=a12f1d21-0a1e-4af2-9b0b-2c7c59d043df]
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the
last "terraform apply" command:
# libvirt_network.net has changed
~ resource "libvirt_network" "net" {
~ autostart = true -> false
id = "a12f1d21-0a1e-4af2-9b0b-2c7c59d043df"
name = "mon-reseau"
}
Would you like to update the Terraform state to reflect these detected changes?
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Terraform vous montre les écarts détectés et demande confirmation. Après le refresh, le state reflète la réalité — mais votre code HCL contient toujours autostart = true. Le prochain plan proposera donc de corriger l’infrastructure.

terraform import rattache une ressource qui existe déjà dans l’infrastructure au state Terraform. Le cas classique : une ressource créée manuellement ou par un autre outil que vous voulez désormais gérer avec Terraform.

  1. Écrire le bloc resource dans le code HCL

    Avant d’importer, le bloc resource correspondant doit exister dans votre configuration :

    resource "libvirt_network" "legacy" {
    name = "legacy-manual-net"
    autostart = true
    forward = {
    mode = "nat"
    }
    ips = [{
    address = "10.10.99.1"
    netmask = "255.255.255.0"
    dhcp = {
    ranges = [{
    start = "10.10.99.100"
    end = "10.10.99.200"
    }]
    }
    }]
    }
  2. Identifier l’ID de la ressource existante

    Chaque provider utilise un format d’ID différent. Pour le provider libvirt, un réseau s’identifie par son UUID :

    Fenêtre de terminal
    virsh net-info legacy-manual-net
    Name: legacy-manual-net
    UUID: d227692a-646f-47a4-8b0a-fefbe48b6601
    Active: yes
    Persistent: yes
    Autostart: yes
    Bridge: virbr-legacy
  3. Exécuter l’import

    Fenêtre de terminal
    terraform import libvirt_network.legacy d227692a-646f-47a4-8b0a-fefbe48b6601
    libvirt_network.legacy: Importing from ID "d227692a-646f-47a4-8b0a-fefbe48b6601"...
    libvirt_network.legacy: Import prepared!
    Prepared libvirt_network for import
    libvirt_network.legacy: Refreshing state... [id=d227692a-646f-47a4-8b0a-fefbe48b6601]
    Import successful!
    The resources that were imported are shown above. These resources are now in
    your Terraform state and will henceforth be managed by Terraform.
  4. Vérifier avec un plan

    Après l’import, un terraform plan peut montrer des différences entre le state importé et votre code HCL :

    Fenêtre de terminal
    terraform plan

    Si le plan affiche No changes, la configuration correspond parfaitement. Sinon, ajustez votre code HCL pour correspondre à la réalité de la ressource, ou appliquez pour aligner l’infrastructure sur votre code.

Alternative déclarative : le bloc import (Terraform >= 1.5)

Section intitulée « Alternative déclarative : le bloc import (Terraform >= 1.5) »

Depuis Terraform 1.5, vous pouvez déclarer un import directement dans le code HCL avec un bloc import. Cette approche est traçable dans le contrôle de version et reproductible en équipe.

import {
to = libvirt_network.legacy
id = "d227692a-646f-47a4-8b0a-fefbe48b6601"
}
resource "libvirt_network" "legacy" {
name = "legacy-manual-net"
autostart = true
# ... reste de la configuration
}

Le prochain terraform plan affiche :

# libvirt_network.legacy will be updated in-place
# (imported from "d227692a-646f-47a4-8b0a-fefbe48b6601")
~ resource "libvirt_network" "legacy" {
autostart = true
name = "legacy-manual-net"
...
}
Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.

Après le apply, la ressource est importée et le bloc import peut être retiré du code :

Apply complete! Resources: 1 imported, 0 added, 1 changed, 0 destroyed.
Critèreterraform importBloc import {}
Version minimaleToutesTerraform >= 1.5
Traçabilité VCSNon (action ponctuelle)Oui (dans le code)
ReproductibilitéNonOui (tout le monde applique)
Revue de codeImpossiblePossible via PR
Usage recommandéImport rapide en soloProjets en équipe

terraform plan -detailed-exitcode retourne un code de sortie différent selon le résultat :

Code de sortieSignification
0Pas de changement — infrastructure synchronisée
1Erreur lors du plan
2Changements détectés — drift ou modifications à appliquer

Quand l’infrastructure est synchronisée :

Fenêtre de terminal
terraform plan -detailed-exitcode
echo "Exit code: $?"
No changes. Your infrastructure matches the configuration.
Exit code: 0

Quand un drift est détecté :

Fenêtre de terminal
terraform plan -detailed-exitcode
echo "Exit code: $?"
# libvirt_network.legacy will be updated in-place
~ resource "libvirt_network" "legacy" {
~ autostart = false -> true
...
}
Plan: 0 to add, 1 to change, 0 to destroy.
Exit code: 2

Vous pouvez intégrer -detailed-exitcode dans un script CI/CD ou un cron pour détecter le drift automatiquement :

#!/bin/bash
terraform plan -detailed-exitcode -no-color > /dev/null 2>&1
EXIT_CODE=$?
case $EXIT_CODE in
0)
echo "OK : infrastructure synchronisée"
;;
1)
echo "ERREUR : impossible d'exécuter le plan"
exit 1
;;
2)
echo "ALERTE : drift détecté, lancer terraform plan pour les détails"
exit 2
;;
esac

Ce script peut être exécuté périodiquement par un pipeline CI/CD pour vous alerter dès qu’une modification manuelle désynchronise l’infrastructure.

SymptômeCause probableSolution
Cannot import non-existent remote objectL’ID fourni ne correspond à aucune ressource existanteVérifier l’ID exact (UUID, ARN, path) dans la console du provider
Plan affiche des changements après importLe code HCL ne correspond pas exactement à la ressource réelleAjuster les attributs du bloc resource ou appliquer pour aligner
Resource already managed by TerraformLa ressource est déjà dans le stateVérifier avec terraform state list avant d’importer ; si vous voulez la rattacher autrement, la retirer d’abord explicitement avec terraform state rm
refresh-only ne détecte rienLa ressource n’a pas été modifiée en dehors de TerraformComparer avec terraform state show et l’état réel
No state file was foundAucun apply effectuéLancer terraform apply d’abord pour créer le state
Format d’ID inconnu pour l’importChaque provider a son propre formatConsulter la doc du provider, section « Import » de chaque ressource
  • Le drift est l’écart entre le state et l’infrastructure réelle — causé par des modifications manuelles ou externes
  • terraform plan détecte le drift, terraform apply le corrige, terraform apply -refresh-only l’accepte
  • terraform import rattache une ressource existante au state — le bloc resource doit exister dans le code avant l’import
  • Le bloc import (Terraform >= 1.5) est l’alternative déclarative, traçable en VCS et reproductible en équipe
  • Le format de l’ID d’import dépend du provider — consultez sa documentation
  • -detailed-exitcode retourne 0 (synchronisé), 1 (erreur) ou 2 (drift) — idéal pour la CI/CD

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn