Chapitre 1415 minIntermédiaire
Terraform et OpenTofu : les notions
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- distinguer provisionnement et gestion de configuration ;
- lire une configuration Terraform simple ;
- expliquer le cycle
init,plan,apply,destroyet le rôle de l'état ; - choisir entre Terraform et OpenTofu, et les combiner avec Ansible.
3 exercices corrigés1 schéma
Terraform et OpenTofu sont des outils d'infrastructure as code qui créent l'infrastructure (machines virtuelles, réseaux, stockage, ressources cloud) à partir de fichiers déclaratifs écrits en HCL, en gardant un état de ce qu'ils ont créé. Ils complètent Ansible, qui configure ensuite les machines. Ce chapitre explique la différence entre provisionnement et gestion de configuration, les notions de Terraform (fournisseur, ressource, plan, état), un exemple sur Proxmox VE, et la façon de combiner les deux outils.
Provisionner ou configurer
On distingue deux étapes dans la vie d'un serveur :
- le provisionnement (provisioning, souvent appelé « jour 0 ») : faire exister la machine, avec son processeur, sa mémoire, son disque, sa carte réseau, son adresse ;
- la gestion de configuration (« jour 1 » et suivants) : installer et régler ce qui tourne dessus, puis le maintenir dans le temps.
| Terraform, OpenTofu | Ansible | |
|---|---|---|
| Métier principal | Créer, modifier, détruire des ressources d'infrastructure | Configurer des systèmes existants, déployer, orchestrer |
| Style | Déclaratif : l'ensemble des ressources voulues | Déclaratif par tâche, procédural par playbook |
| Langage | HCL (HashiCorp Configuration Language) | YAML et Jinja2 |
| Mémoire de ce qui existe | Un fichier d'état (terraform.tfstate) | Aucune : chaque exécution observe l'état réel |
| Avant d'agir | plan : la liste exacte de ce qui sera créé, modifié, détruit | --check --diff : une simulation, moins complète |
| Supprimer ce qui n'est plus décrit | Oui : une ressource retirée du code est détruite | Non : il faut écrire une tâche state: absent |
| Cible | API (Proxmox, VMware, clouds, DNS, pare-feu…) | SSH, WinRM, API |
L'état fait la différence. Ansible ne se souvient de rien : si tu retires une VM de ton playbook, elle continue d'exister. Terraform sait ce qu'il a créé : si tu retires la VM du code, le plan suivant annonce sa destruction.
Terraform et OpenTofu
Terraform a été créé par HashiCorp en 2014. En août 2023, HashiCorp a remplacé sa licence libre (MPL 2.0) par la Business Source License (BSL 1.1) à partir de la version 1.6 : le code reste lisible et utilisable en interne, mais n'est plus un logiciel libre au sens de l'OSI, et ne peut pas servir à bâtir un produit concurrent. HashiCorp appartient à IBM depuis 2025. En novembre 2026, la version courante est la 1.17.
OpenTofu est le fork libre de Terraform, né de ce changement de licence à partir de la dernière version sous MPL 2.0. Il est hébergé par la Linux Foundation et accepté à la CNCF depuis 2025. Il garde le même langage, les mêmes fichiers et la même compatibilité avec les fournisseurs ; la commande s'appelle tofu au lieu de terraform. Sa version courante est la 1.13.
Pour un laboratoire ou une PME, les deux conviennent ; OpenTofu a l'avantage d'une licence libre et d'une gouvernance ouverte. Tout ce chapitre s'applique aux deux, en remplaçant terraform par tofu dans les commandes.
Les notions de base
| Notion | Définition | Exemple |
|---|---|---|
| Fournisseur (provider) | Le greffon qui sait parler à une API | bpg/proxmox pour Proxmox VE |
| Ressource (resource) | Un objet d'infrastructure à créer et gérer | Une VM, un enregistrement DNS |
| Source de données (data source) | Une information lue sans être gérée | La liste des nœuds du cluster |
| Variable | Une valeur d'entrée | Le jeton d'API, le nombre de VM |
| Sortie (output) | Une valeur affichée ou transmise à la fin | L'adresse de la VM créée |
| État (state) | Le fichier qui mémorise les ressources créées et leurs attributs | terraform.tfstate |
| Module | Un ensemble réutilisable de ressources | « Une VM Debian standard » |
Le cycle de travail tient en quatre commandes :
terraform init # télécharge les fournisseurs, prépare le dossier
terraform plan # compare le code, l'état et la réalité : affiche ce qui va changer
terraform apply # applique le plan, après confirmation
terraform destroy # détruit tout ce que le code a créé
plan est le moment clé : il dit exactement, ressource par ressource, ce qui sera créé (+), modifié (~), détruit (-) ou remplacé (-/+, détruit puis recréé), avec un résumé du type Plan: 1 to add, 0 to change, 0 to destroy. On relit le plan avant de valider ; en équipe, on le joint à la demande de fusion.
Un exemple sur Proxmox VE
Le fournisseur communautaire bpg/proxmox est aujourd'hui le plus utilisé pour Proxmox VE (l'ancien fournisseur telmate/proxmox est très peu maintenu). Le fichier main.tf qui crée la même VM de recette qu'au chapitre 13, avec le même jeton d'API :
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "~> 0.120"
}
}
}
variable "jeton_proxmox" {
description = "Jeton d'API, au format ansible@pve!automatisation=secret"
type = string
sensitive = true
}
provider "proxmox" {
endpoint = "https://192.168.10.213:8006/"
api_token = var.jeton_proxmox
insecure = true
}
resource "proxmox_virtual_environment_vm" "recette" {
name = "srv-recette"
node_name = "pve1"
vm_id = 186
clone {
vm_id = 9000
full = true
}
cpu {
cores = 4
}
memory {
dedicated = 8192
}
disk {
datastore_id = "truenas-nfs"
interface = "scsi0"
size = 40
}
network_device {
bridge = "vmbr0"
vlan_id = 21
}
initialization {
datastore_id = "truenas-nfs"
ip_config {
ipv4 {
address = "192.168.21.186/24"
gateway = "192.168.21.254"
}
}
dns {
domain = "ad.sorbier.example"
servers = ["192.168.10.177", "192.168.10.181"]
}
user_account {
username = "ansible"
keys = [trimspace(file(pathexpand("~/.ssh/ansible_ed25519.pub")))]
}
}
}
output "adresse_recette" {
value = "192.168.21.186"
}
Lis-le comme un inventaire de ce qui doit exister : un bloc terraform qui déclare le fournisseur et sa version, une variable sensible (sa valeur n'apparaît pas dans les sorties), le fournisseur configuré, puis une ressource de type proxmox_virtual_environment_vm, nommée recette dans le code, dont chaque bloc décrit une partie de la VM. insecure = true accepte le certificat auto-signé de Proxmox, comme validate_certs: false côté Ansible.
Le secret ne s'écrit pas dans le fichier : il passe par une variable d'environnement, que Terraform lit automatiquement pour la variable du même nom.
export TF_VAR_jeton_proxmox='ansible@pve!automatisation=a1b2c3d4-e5f6-7890-abcd-ef1234567890'
terraform init
terraform plan
terraform apply
Change ensuite cores = 4 en cores = 2 : le plan annonce une modification en place (~). Supprime le bloc resource : le plan annonce une destruction. C'est ce suivi qui fait l'intérêt de l'outil.
L'état : précieux et sensible
Le fichier terraform.tfstate est la mémoire de Terraform. S'il est perdu, Terraform ne sait plus qu'il a créé la VM et voudra la recréer ; si deux personnes l'utilisent en même temps, il peut être corrompu.
- Ne le mets pas dans Git. Il contient les attributs des ressources, souvent des secrets en clair. Il va dans le
.gitignore, avec le dossier.terraform/des fournisseurs téléchargés. - En équipe, range-le dans un backend distant avec verrouillage : un stockage objet compatible S3, la base PostgreSQL d'un serveur interne, ou le service de l'éditeur. Chaque exécution prend un verrou, et les autres attendent.
- OpenTofu sait chiffrer l'état côté client ; Terraform n'a pas cette fonction et compte sur le chiffrement du backend qui stocke l'état.
Terraform et Ansible ensemble
Les deux outils se complètent naturellement : Terraform crée les VM, Ansible les configure.
Trois façons de faire passer les adresses de Terraform à Ansible :
- Les sorties de Terraform (
terraform output -json) lues par un script qui écrit l'inventaire ; - un inventaire dynamique qui interroge directement l'hyperviseur, comme celui du chapitre 13 ;
- le DNS : les VM sont déclarées dans le DNS et l'inventaire utilise leurs noms.
Le dépôt de Sorbier range les deux outils côte à côte (terraform/ et le reste du projet Ansible), et le pipeline d'intégration continue vérifie les deux (chapitre 15).
Exercices
Exercice 1 sur 3 Quel outil ? Réussi À revoir
Pour chaque tâche, dis si elle relève plutôt de Terraform ou OpenTofu, ou plutôt d'Ansible.
- Créer trois VM sur le cluster Proxmox et les supprimer quand le projet se termine.
- Installer Apache et déployer l'hôte virtuel du site de suivi.
- Créer les enregistrements DNS d'une zone publique chez un hébergeur qui propose une API.
- Créer 25 comptes Active Directory à partir d'une liste.
- Ajouter 4 Gio de mémoire à une VM existante créée par Terraform.
Voir la réponseMasquer la réponse de l'exercice 1
- Terraform ou OpenTofu : création et destruction de ressources, suivies par l'état.
- Ansible : configuration du système.
- Terraform ou OpenTofu : ce sont des ressources d'infrastructure exposées par une API, et l'état permet de supprimer proprement un enregistrement retiré du code. Ansible sait aussi le faire avec un module de l'hébergeur.
- Ansible (
microsoft.ad.user) : on configure un service existant, l'annuaire. - Terraform : la VM est décrite dans son code ; il faut y changer
dedicated. La modifier par Ansible ou à la main créerait un écart que le plan suivant voudrait annuler.
Tu avais trouvé ?
Exercice 2 sur 3 Lire un plan Réussi À revoir
Après une modification du code, terraform plan affiche pour la VM de recette -/+ resource "proxmox_virtual_environment_vm" "recette" et le résumé Plan: 1 to add, 0 to change, 1 to destroy. Que va-t-il se passer si tu valides ? Que fais-tu avant ?
Voir la réponseMasquer la réponse de l'exercice 2
-/+ signifie remplacement : Terraform va détruire la VM 186 puis en créer une nouvelle. Le résumé le confirme : une destruction et une création. Toutes les données de la VM (et sa configuration faite par Ansible) seront perdues. Avant de valider : chercher dans le plan quel attribut force le remplacement (Terraform l'indique par # forces replacement), se demander si la modification est vraiment voulue ou si un changement en place est possible, et vérifier qu'une sauvegarde récente existe. Sur une VM de recette jetable, c'est acceptable ; sur une VM de production, jamais sans préparation.
Tu avais trouvé ?
Exercice 3 sur 3 L'état dans Git ? Réussi À revoir
Moussa propose de commiter terraform.tfstate dans le dépôt, « pour que tout le monde ait le même état ». Donne deux raisons de refuser et la bonne solution.
Voir la réponseMasquer la réponse de l'exercice 3
- Les secrets : l'état contient les attributs des ressources, parfois des mots de passe ou des clés en clair ; il serait lisible par tous ceux qui lisent le dépôt, et resterait dans l'historique.
- Les conflits et la corruption : deux administrateurs qui appliquent en même temps à partir de deux copies de l'état divergent ; Git ne sait pas fusionner un état, et l'un écrase le travail de l'autre.
La bonne solution est un backend distant avec verrouillage (stockage objet compatible S3, PostgreSQL, service de l'éditeur), accessible aux seuls administrateurs, et le fichier terraform.tfstate dans le .gitignore.
Tu avais trouvé ?