DevOps Elastic Hayway
Document

SUBSCRIBE TO GET FULL ACCESS TO THE E-BOOKS FOR FREE 🎁SUBSCRIBE NOW

Professional Dropdown with Icon

SUBSCRIBE NOW TO GET FREE ACCESS TO EBOOKS

TerraformLesson 9 / 244 min readUpdated September 13, 2026

Locals Terraform : valeurs dérivées propres

À la fin de ce tutoriel, vous saurez distinguer locals (valeurs dérivées) et variables (entrées), déclarer un bloc locals avec expressions, construire common_tags et name_prefix pour un lab S3 en Region ca-central-1, référencer local.xxx vs var.xxx, et éviter sur-abstraction, dépendances circulaires et locals non définis.

Niveau : Débutant · Temps estimé : 30–40 min · Versions testées : Terraform 1.16.2 (série ≥ 1.9), AWS provider ~> 5.0 · Dernière vérification : 2026-09-10

Slug proposé : terraform-locals · Série : Terraform · Remplace / fusionne : #1640

Prérequis

  • Avoir suivi Variables (terraform-variables) : bloc variable, types, tfvars, var.NOM
  • Avoir suivi Providers et ressources (terraform-providers-ressources) et Blocs HCL (terraform-blocs-hcl)
  • Terraform ≥ 1.9, AWS CLI v2, profil de lab prêt (aws sts get-caller-identity OK)

Coût estimé : 0 € si vous vous arrêtez à init / plan (recommandé). Un apply créerait un bucket S3 (Free Tier / faible coût) : destroy obligatoire. Aucun secret dans le HCL ni dans les tfvars commités.

Auth sans secrets. Utilisez AWS_PROFILE / SSO. Jamais d’access_key / secret_key dans le provider. Les locals ne sont pas un coffre-fort : n’y placez pas de mots de passe.

Ce que nous allons construire

Lab locals Terraform (ca-central-1)
  ├── versions.tf / providers.tf → aws ~> 5.0, region ca-central-1
  ├── variables.tf     → entrées (project, environment, owner…)
  ├── locals.tf        → name_prefix, common_tags, bucket_name
  ├── main.tf          → bucket S3 via local.* (pas de duplication)
  └── init → plan (vérifier tags et nom dérivés)

(Schéma à remplacer par une image locale Excalidraw / draw.io, alt : « Locals Terraform : valeurs dérivées, common_tags et name_prefix ».)

Ce guide révise et actualise le post #1640 : locals Terraform 1.9+ pour dériver noms et tags — sans rejouer variables/providers ni anticiper outputs.

Étape 1 — Locals vs variables

Les débutants confondent souvent « j’ai besoin d’une valeur » avec « l’appelant doit choisir cette valeur ». Si l’opérateur doit pouvoir changer l’environnement via tfvars, c’est une variable. Si le module calcule "${project}-${environment}" pour éviter la duplication, c’est un local. Mélanger les deux produit soit des modules rigides (tout en dur), soit des interfaces bruyantes (dix variables qui ne font que renvoyer la même concaténation).

Cas réel : trois resources (S3, log group, rôle IAM) répètent le même préfixe. Un rename de projet oblige trois edits et risque d’oublier un tag. Un local.name_prefix unique corrige les trois d’un coup — c’est exactement la promesse des locals Terraform.

Variables (var.) Locals (local.)
Rôle Entrées paramétrables (tfvars, -var, TF_VAR_) Valeurs dérivées calculées dans le module
Qui les fixe Opérateur / CI / appelant du module Auteur du module (expressions HCL)
Exemple var.environment = "lab" local.name_prefix = "${var.project}-${var.environment}"
Sensible ? sensitive = true possible Héritent de la sensibilité des expressions

Sans locals, vous répétez "${var.project}-${var.environment}" et le même merge de tags dans chaque ressource. Une typo et les noms divergent. Les locals centralisent ces formules : une seule source de vérité pour le préfixe, les tags communs ou une map dérivée.

Règle simple : variable = ce que l’appelant choisit ; local = ce que le module calcule à partir de ces choix (et éventuellement de data sources). Les outputs exposeront ensuite des résultats — prochain tutoriel.

Étape 2 — Bloc locals : syntaxe et expressions

La convention locals.tf aide la navigation, mais Terraform accepte plusieurs blocs locals fusionnés tant que les noms restent uniques. Référez toujours avec local. (singulier). Les expressions peuvent s’appuyer sur d’autres locals : gardez un graphe acyclique et des noms métier (common_tags, bucket_name) plutôt que tmp1 / x.

Déclarez les dérivés dans locals.tf (convention) :

locals {
  name_prefix = "${var.project}-${var.environment}"

  common_tags = {
    Project     = var.project
    Environment = var.environment
    Owner       = var.owner
    ManagedBy   = "terraform"
  }

  # Concaténation + suffixe unique (à adapter)
  bucket_name = "${local.name_prefix}-assets-SUFFIXE-UNIQUE"

  # Map dérivée : tags communs + Name
  bucket_tags = merge(
    local.common_tags,
    {
      Name    = local.bucket_name
      Purpose = "terraform-locals-lab"
    }
  )
}
  • Un module peut avoir plusieurs blocs locals : Terraform les fusionne (noms uniques requis).
  • À l’intérieur, vous utilisez interpolations, merge, join, format, ternaires, for…
  • Référencez avec local.NOM (singulier), jamais locals.NOM.
  • Les locals peuvent s’enchaîner : local.bucket_name s’appuie sur local.name_prefix — ordre logique, pas d’ordre d’écriture strict, mais pas de cycle.

Étape 3 — Cas d’usage concrets

Nommage, tags, chemins de logs et maps fusionnées couvrent 90 % des besoins débutant/intermédiaire. Résistez à l’envie de créer une « librairie » de locals pour chaque fonction HCL : si une expression n’est utilisée qu’une fois, un inline peut suffire. Les locals excellents sont ceux que vous relisez trois mois plus tard sans décoder un DSL maison.

1. Nommage cohérent — un name_prefix unique pour buckets, rôles IAM, logs :

locals {
  name_prefix = lower("${var.project}-${var.environment}")
}

2. Tags communs — common_tags + merge sur chaque ressource (ou default_tags provider + locals pour le Name) :

tags = merge(local.common_tags, { Name = local.name_prefix })

3. Concaténations / chemins — ARN partiels, clés S3, labels CloudWatch :

locals {
  log_group = "/aws/${var.project}/${var.environment}/app"
}

4. Maps dérivées — filtrer ou enrichir une map d’entrée :

locals {
  required_tags = {
    CostCenter = var.cost_center
    Compliance = "required"
  }
  all_tags = merge(var.extra_tags, local.required_tags, local.common_tags)
}

Ces patterns réduisent la duplication sans transformer le module en DSL opaque — voir l’étape 4.

Étape 4 — Quand NE PAS utiliser les locals

La sur-abstraction est le principal anti-pattern : cacher une vraie entrée utilisateur, empiler des alias local.project = var.project, ou stocker un secret « parce que ce n’est pas une variable ». Les locals apparaissent dans le state comme le reste : ce ne sont pas un coffre. Pour les secrets, SSM / Secrets Manager + IAM restent la voie saine (terraform-rds illustre le pattern mot de passe).

Les locals sont puissants ; l’abus produit de la sur-abstraction :

  • Ne pas cacher une entrée utilisateur derrière un local « magique » : si l’appelant doit choisir, utilisez variable.
  • Ne pas empiler dix locals qui ne font que renvoyer var.xxx inchangé — bruit sans valeur.
  • Ne pas recréer une mini-bibliothèque de fonctions HCL illisibles : préférez 2–3 locals nommés clairement.
  • Ne pas y stocker des secrets (même dérivés) : le state reste en clair côté backend non chiffré.
  • Évitez les locals qui dépendent de ressources créées dans le même module de façon circulaire (voir erreurs).

Bon équilibre : locals pour répétition réelle (préfixe, tags, nom de bucket) ; variables pour paramètres ; expressions inline pour un usage unique.

Étape 5 — Lab ca-central-1 : common_tags + name_prefix

Le lab S3 est volontairement minimal : vous devez voir dans le plan que le nom et les tags viennent des locals. Changez environment via -var et observez le recalcul sans éditer main.tf. Si vous appliquez, force_destroy = true facilite le cleanup de lab — ne recopiez pas ce flag aveuglément en prod.

mkdir -p ~/terraform-locals-lab && cd ~/terraform-locals-lab
export AWS_PROFILE=lab
export AWS_REGION=ca-central-1
aws sts get-caller-identity

versions.tf — required_version = ">= 1.9.0", hashicorp/aws ~> 5.0.

providers.tf — region = "ca-central-1", éventuellement default_tags Project/ManagedBy ; aucune clé.

variables.tf :

variable "project" {
  type        = string
  description = "Nom court du projet (préfixe de ressources)."
  default     = "deh"
}

variable "environment" {
  type        = string
  description = "Environnement court."
  default     = "lab"

  validation {
    condition     = contains(["lab", "dev", "staging"], var.environment)
    error_message = "environment doit être lab, dev ou staging."
  }
}

variable "owner" {
  type        = string
  description = "Responsable / équipe."
  default     = "devopselastichayway"
}

variable "extra_tags" {
  type        = map(string)
  description = "Tags additionnels fusionnés avec common_tags."
  default     = {}
}

locals.tf — bloc de l’étape 2 (name_prefix, common_tags, bucket_name, bucket_tags). Remplacez SUFFIXE-UNIQUE (initiales + date).

main.tf :

resource "aws_s3_bucket" "lab_locals" {
  bucket        = local.bucket_name
  force_destroy = true

  tags = local.bucket_tags
}

resource "aws_s3_bucket_public_access_block" "lab_locals" {
  bucket = aws_s3_bucket.lab_locals.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}
terraform init && terraform fmt -recursive && terraform validate && terraform plan

Dans le plan, vérifiez que le nom du bucket et les tags (Project, Environment, Owner, ManagedBy, Name, Purpose) correspondent aux locals. Pas d’obligation d’apply ; si vous appliquez, enchaînez un destroy. Override d’entrée : terraform plan -var='environment=dev' — le name_prefix et les tags se recalculent seuls.

Étape 6 — local.xxx vs var.xxx

terraform console est votre allié pour lever le doute en trente secondes. Dans un module enfant, tout arrive d’abord en inputs (variable) : mappez explicitement ce que le parent passe, puis redérivez des locals locaux au module. Évitez de « fuiter » des locals parents non documentés.

Expression Signification
var.environment Valeur d’entrée (default / tfvars / CLI)
local.name_prefix Valeur dérivée dans un bloc locals
local.common_tags["Owner"] Accès map sur un local
aws_s3_bucket.lab_locals.id Attribut de ressource (pas un local)

Erreurs de préfixe fréquentes : écrire locals.name_prefix (pluriel) ou var.name_prefix alors que name_prefix est un local. Dans terraform console :

terraform console
> local.name_prefix
> var.environment

Les modules enfants reçoivent des variables (inputs) ; à l’intérieur du module enfant vous pouvez à nouveau définir des locals. Ne passez pas un local parent « tel quel » sans le mapper sur une variable enfant si vous encapsulez.

Étape 7 — Checklist

Avant Outputs, confirmez : entrées en var, formules répétées en local, références au singulier, merge de tags cohérent, aucun secret, aucun cycle. Cette hygiène rend le prochain tuto (outputs) trivial : vous exposerez des dérivés déjà propres.

  1. Entrées utilisateur en variable ; formules répétées en locals.
  2. Fichier locals.tf (ou bloc clair) avec noms explicites (name_prefix, common_tags).
  3. Références local.NOM (singulier).
  4. merge pour tags : communs + spécifiques ressource.
  5. Pas de secret dans les locals ; pas de sur-abstraction.
  6. Aucune dépendance circulaire entre locals / ressources.
  7. init → fmt → validate → plan ; destroy si apply.

Nettoyage

Sans apply : rm -rf ~/terraform-locals-lab. Avec apply : terraform destroy, vérifiez l’absence du bucket en ca-central-1, puis supprimez le dossier.

Erreurs fréquentes

Symptôme Cause Correction
Reference to undeclared local Typo ou local jamais déclaré Vérifiez le nom dans locals { } ; local.xxx pas locals.xxx
Cycle / circular reference Local A → B → A, ou local ↔ ressource Cassez le cycle : calculez avant la ressource, ou utilisez un output/data
Invalid reference var.name_prefix Préfixe traité comme variable Utilisez local.name_prefix
Tags incomplets sur une ressource Oubli de merge(local.common_tags, …) Centralisez via local.bucket_tags
Nom de bucket invalide Suffixe / caractères hors règles S3 lower(), validation sur var.project, suffixe unique
Sur-abstraction Chaîne de locals illisibles Gardez 3–5 locals métier max pour un lab
merge écrase un tag voulu Ordre des maps dans merge Placer les tags spécifiques après les communs
Nom S3 globalement pris Préfixe trop générique Suffixe unique (compte / initiales / date)
Local sensible fuité en CI Output non sensitive Marquer outputs / éviter d’echo le state

Quiz (3 questions)

1. Quelle est la différence principale entre var et local ?

  • A. Aucune — ce sont des alias
  • B. var = entrée paramétrable ; local = valeur dérivée dans le module
  • C. local est toujours sensible, var ne l’est jamais

2. Comment référence-t-on un local nommé common_tags ?

  • A. locals.common_tags
  • B. var.common_tags
  • C. local.common_tags

3. Quand faut-il éviter les locals ?

  • A. Pour un préfixe de nom répété trois fois
  • B. Quand cela crée une sur-abstraction ou cache une vraie entrée utilisateur
  • C. Pour fusionner des tags communs

4. Quelle expression est correcte pour un local name_prefix ?

  • A. locals.name_prefix
  • B. local.name_prefix
  • C. var.local.name_prefix

5. Pourquoi éviter de stocker un mot de passe dans un local ?

  • A. Syntaxe interdite par Terraform 1.9
  • B. Le state n’est pas un coffre — risque de fuite
  • C. Les locals ne supportent pas les strings

Réponses : 1‑B · 2‑C · 3‑B · 4‑B · 5‑B

FAQ

Locals vs default_tags du provider ? default_tags applique un socle à toutes les resources AWS du provider. Les locals restent utiles pour des Name / Purpose spécifiques ou des fusions fines. Les deux se complètent.

Puis-je mettre un data dans un local ? Oui : local.account_id = data.aws_caller_identity.current.account_id est un pattern courant (voir aussi l’exemple variables + data sources). Attention aux cycles si le data dépend d’une resource du même module de façon circulaire.

Combien de locals « trop » ? Pas de chiffre magique. Si vous ne savez plus quel local lire pour un tag, simplifiez. Trois à cinq locals métier suffisent souvent à un root module de lab.

Pour aller plus loin

  • Doc : Local Values, Expressions, Input Variables
  • Sur ce site : Outputs, révisez Variables, Providers, Blocs HCL
  • Rappel : un local clair vaut mieux que dix interpolations copiées-collées

Maillage série Terraform (P2)

← Précédent Variables (terraform-variables)
→ Suivant Outputs (terraform-outputs)
Aussi Providers (terraform-providers-ressources) · Blocs HCL (terraform-blocs-hcl)
Carte Overview · Install · Workflow · Blocks · Providers · Variables · Locals · Outputs · State · Data sources · Loops · Conditionals · Dynamic blocks · Modules ×2 · Workspaces · Provisioners · EBS · ELB/ALB · IAM · RDS · VPC · Auto Scaling · Route 53

Retour parcours Terraform — hub de la série et leçons sœurs.

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *