Aller au contenu
Infrastructure as Code medium

Style guide Terraform : conventions officielles et CI

20 min de lecture

logo terraform

Un style guide ne se relit pas, il se fait rejeter par une CI. Les noms de fichiers ne changent rien au comportement de Terraform, donc les vérifier ne prouve rien ; ce qui prouve, c'est le code retour de terraform fmt -check et le JSON de terraform validate. Ce guide reprend le style guide officiel, en corrigeant les points où la pratique courante s'écarte de la source.

Il couvre le nommage des fichiers et des ressources, l'ordre des paramètres, les commentaires, le typage des outputs, le .gitignore, et l'outillage (fmt, validate, TFLint, pré-commit). Les comportements cités ont été vérifiés sur Terraform v1.15.4.

  • Le nommage des fichiers officiel, et ses exceptions
  • Nommer une ressource, et le mythe de this
  • L'ordre des ressources et des paramètres (depends_on en dernier)
  • Le commentaire idiomatique, et le typage des outputs (1.15)
  • Le .gitignore qui sort le state mais garde le lock
  • fmt, validate, TFLint et les hooks de pré-commit
  • Un projet Terraform initialisé (installer Terraform)
  • Terraform 1.15.x, la série stable courante

Terraform concatène tous les .tf d'un dossier : la découpe est une convention de lisibilité, sans effet technique, à deux exceptions près. Le style guide officiel recommande cette structure :

FichierContenu
terraform.tfle bloc terraform (required_version, required_providers)
providers.tftous les blocs provider
variables.tftoutes les variables, en ordre alphabétique
main.tfressources et data sources
outputs.tftous les outputs, en ordre alphabétique

Le nom officiel du fichier portant le bloc terraform est terraform.tf, pas versions.tf : c'est une confusion répandue. On peut aussi séparer le backend dans un backend.tf, et déclarer plusieurs blocs terraform.

Les deux cas où le nom a un effet : les fichiers *_override.tf (et override.tf) sont chargés en dernier et fusionnés par-dessus le reste ; et un dépôt de module publié doit s'appeler terraform-<PROVIDER>-<NOM>, imposé par le registre.

Une ressource se nomme avec un nom descriptif en snake_case, sans répéter le type que l'adresse porte déjà :

# bien : l'adresse est random_pet.serveur
resource "random_pet" "serveur" {}
# mal : camelCase, et le nom repete le type
resource "random_pet" "randomPetServeur" {}

Le nom this pour la ressource unique d'un module est une convention communautaire répandue, mais le style guide officiel ne le mentionne jamais : il demande seulement « a descriptive noun and separate words with underscores ». Le présenter comme une règle officielle est un abus.

Deux ordres officiels sont souvent inversés. D'abord, les ressources dépendantes se déclarent APRÈS celles qu'elles référencent (« let your code build on itself »), et une data source avant la ressource qui la consomme.

Ensuite, à l'intérieur d'un bloc resource, l'ordre officiel des paramètres est :

  1. count ou for_each, si présent ;
  2. les arguments non-bloc de la ressource ;
  3. les arguments de type bloc ;
  4. un bloc lifecycle, si besoin ;
  5. depends_on en DERNIER, si besoin.

HCL accepte #, // et /* */, mais la doc tranche : seul # est idiomatique, en une ligne comme en plusieurs. « The // and /* */ comment syntaxes are not considered idiomatic, but Terraform supports them to remain backward-compatible with earlier versions of HCL. » Les deux autres ne survivent que par compatibilité ascendante ; ne les recommandez pas.

Depuis Terraform 1.15, le style guide demande un type et une description sur chaque output, comme pour les variables. Le type n'est pas cosmétique. Vérifié en 1.15.4 : un output type = number dont la valeur vient d'un terraform.tfvars qui l'écrit "2" (entre guillemets) ressort en JSON avec "type": "number", "value": 2, contre "type": "string", "value": "2" sans la déclaration.

output "nombre_noeuds" {
type = number
description = "Nombre de noeuds."
value = var.nombre_noeuds
}

L'ordre officiel des paramètres est type, description, default, sensitive, validation pour une variable ; type, description, value, sensitive pour un output.

C'est la seule règle du style guide dont l'oubli a des conséquences de sécurité immédiates. On n'committe jamais : le répertoire .terraform/, les fichiers terraform.tfstate*, .terraform.tfstate.lock.info, les plans sauvegardés par -out, et tout .tfvars sensible. On committe en revanche .terraform.lock.hcl, le fichier de verrouillage des versions de providers.

.terraform/
terraform.tfstate
terraform.tfstate.*
.terraform.tfstate.lock.info
*.tfplan
*.tfvars
!.terraform.lock.hcl

Deux commandes, deux rôles distincts :

  • terraform fmt normalise l'indentation, aligne les =, espace les maps inline. terraform fmt -check sort en code 3 (pas 1) quand un fichier n'est pas formaté, vérifié en 1.15.4.
  • terraform validate vérifie la cohérence interne et les types, mais ne valide pas les valeurs auprès du provider et **n'**évalue pas le state.

Terraform n'a pas de linter intégré : la doc recommande TFLint. Et le bon endroit pour lancer fmt et validate est un hook de pré-commit Git, là où l'erreur se corrige le moins cher, avant même la CI.

Le style guide officiel a une seconde moitié, souvent oubliée : le workflow style. Elle couvre la structure de dépôt (un module par dépôt), la stratégie de branches, la gestion des environnements multiples, le partage de state entre configurations, les tests de modules et les politiques d'enforcement. Pour un profil Professional, cette partie recoupe directement les sous-objectifs sur le state distant et les workflows d'équipe.

Ces symptômes se lisent tous avant la CI. Le tableau associe chaque écart de style à sa cause.

SymptômeCauseSolution
terraform fmt -check sort en code 3Un fichier n'est pas formatéLancer terraform fmt (idéalement en pré-commit)
validate échoue sur une référence inconnueUne variable ou ressource référencée mais non déclaréeDéclarer l'objet, ou corriger le nom
.terraform.lock.hcl absent du dépôtIgnoré par .terraform*Ignorer le répertoire par .terraform/, garder le lock
Un output number sort en chaînePas de contrainte typeDéclarer type = number sur l'output
Un depends_on en tête déroute la relectureOrdre non conformeLe placer en dernier, après lifecycle
  1. Le bloc terraform va dans terraform.tf, pas versions.tf.
  2. Une ressource se nomme en snake_case descriptif ; this est une convention communautaire, pas officielle.
  3. Les ressources dépendantes se déclarent après leurs références ; depends_on en dernier dans un bloc.
  4. Seul # est un commentaire idiomatique.
  5. Depuis 1.15, typez les outputs comme les variables.
  6. Le .gitignore sort le state mais garde .terraform.lock.hcl ; gare à .terraform*.
  7. fmt formate, validate vérifie les types (pas les valeurs provider), TFLint lint, le pré-commit automatise.

Les questions ci-dessous reprennent les confusions les plus fréquentes du style guide : le nom du fichier terraform, la place de depends_on, et le .gitignore.

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn