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
localsavec expressions, construirecommon_tagsetname_prefixpour un lab S3 en Regionca-central-1, référencerlocal.xxxvsvar.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) : blocvariable, 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-identityOK)
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_keydans 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), jamaislocals.NOM. - Les locals peuvent s’enchaîner :
local.bucket_names’appuie surlocal.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.xxxinchangé — 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.
- Entrées utilisateur en
variable; formules répétées enlocals. - Fichier
locals.tf(ou bloc clair) avec noms explicites (name_prefix,common_tags). - Références
local.NOM(singulier). mergepour tags : communs + spécifiques ressource.- Pas de secret dans les locals ; pas de sur-abstraction.
- Aucune dépendance circulaire entre locals / ressources.
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.
localest toujours sensible,varne 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.



