Variables Terraform : input types et validation
À la fin de ce tutoriel, vous saurez déclarer des variables d’entrée (
variable), choisir les types (string, number, bool, list, map, object, set), ajouterdefault,description,sensitive,nullableet des blocs de validation, puis comprendre la priorité d’assignation (default → tfvars →-var→TF_VAR_) avec un lab S3 en Regionca-central-1(préfixe de bucket et tags via variables).Niveau : Débutant · Temps estimé : 35–45 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-variables· Série : Terraform · Remplace / fusionne : #1635
Prérequis
- Avoir suivi Providers et ressources (
terraform-providers-ressources) :required_providers, provider AWS, adresseTYPE.NAME - Avoir suivi Blocs HCL (
terraform-blocs-hcl) et Workflow Terraform (terraform-workflow) - 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 ni de mots de passe dans*.tfvarsversionnés.
Ce que nous allons construire
Lab variables Terraform (ca-central-1)
├── versions.tf / providers.tf → aws ~> 5.0, region ca-central-1
├── variables.tf → types, defaults, sensitive, validation
├── terraform.tfvars → valeurs lab (préfixe, tags)
├── main.tf → bucket S3 paramétré via var.*
└── init → plan (+ priorité d’assignation)
(Schéma à remplacer par une image locale Excalidraw / draw.io, alt : « Variables Terraform : déclaration, types, validation et priorité d’assignation ».)
Ce guide révise et actualise le post #1635 : variables d’entrée Terraform 1.9+, types et validation — sans rejouer providers/ressources ni anticiper locals/outputs.
Étape 1 — Pourquoi des variables ?
Sans variables, chaque environnement (lab, staging, prod) duplique le HCL : noms de buckets, tags, tailles… Une typo et les configs divergent.
Les variables d’entrée (variable) rendent le module réutilisable : le même code reçoit des valeurs différentes selon l’environnement. Vous paramétrez un préfixe de bucket, des tags ou un booléen « activer versioning » sans réécrire les resource.
Avantages : réutilisabilité, environnements distincts sans fork de code, clarté via description + validation, et sensible pour masquer les secrets dans les logs (sans remplacer un coffre-fort). Les variables ne remplacent pas les locals (dérivés) ni les outputs (expositions) — prochains tutoriels.
Étape 2 — Bloc variable : attributs essentiels
Déclarez chaque entrée dans variables.tf (convention) :
variable "bucket_prefix" {
type = string
description = "Préfixe du nom de bucket S3 (minuscules, chiffres, tirets)."
default = "deh-lab"
nullable = false
sensitive = false
validation {
condition = can(regex("^[a-z0-9][a-z0-9-]{1,20}$", var.bucket_prefix))
error_message = "bucket_prefix doit être un préfixe S3 valide (2–21 caractères)."
}
}
| Attribut | Rôle |
|---|---|
type |
Contrainte (string, number, bool, list, map, object, set…) |
default |
Valeur si rien n’est fourni ailleurs (rend la variable optionnelle) |
description |
Documentation affichée dans le plan / l’UI |
sensitive |
Masque la valeur dans CLI et logs (ne chiffre pas le state) |
nullable |
Si false, refuse null même avec un default |
Sans default, Terraform exige une valeur (tfvars, -var ou TF_VAR_). Référencez toujours avec var.NOM.
Étape 3 — Types courants
variable "environment" {
type = string
description = "Nom d’environnement court."
default = "lab"
}
variable "retention_days" {
type = number
default = 7
}
variable "enable_versioning" {
type = bool
default = false
}
variable "availability_zones" {
type = list(string)
default = ["ca-central-1a", "ca-central-1b"]
}
variable "extra_tags" {
type = map(string)
default = {
Owner = "devopselastichayway"
Stage = "variables-lab"
}
}
variable "bucket_config" {
type = object({
force_destroy = bool
purpose = string
})
default = {
force_destroy = true
purpose = "terraform-variables-lab"
}
}
variable "allowed_stages" {
type = set(string)
default = ["lab", "dev", "staging"]
}
- Scalaires :
string,number,bool. list(T): séquence ordonnée (var.availability_zones[0]).map(T): clés → valeurs (var.extra_tags["Owner"]).object({…}): structure nommée pour regrouper des options.set(T): sans doublons ni ordre stable.
Un mauvais type (string là où un number est attendu) échoue avant l’appel API.
Étape 4 — Blocs validation personnalisés
La condition doit être booléenne et ne référencer que la variable validée :
variable "environment" {
type = string
default = "lab"
validation {
condition = contains(["lab", "dev", "staging"], var.environment)
error_message = "environment doit être lab, dev ou staging."
}
}
variable "retention_days" {
type = number
default = 7
validation {
condition = var.retention_days >= 1 && var.retention_days <= 90
error_message = "retention_days doit être entre 1 et 90."
}
}
Si la condition est fausse, Terraform affiche error_message et s’arrête — première défense contre un préfixe S3 invalide ou un enum hors liste.
Étape 5 — Priorité d’assignation
Du plus faible au plus fort :
defaultdans le blocvariable- **
*.auto.tfvars** (ordre alphabétique) terraform.tfvars/.json-var-file=…(ordre CLI)-var='name=value'TF_VAR_name(souvent en CI ; testez les conflits avec un plan)
Pratique lab : defaults sûrs dans variables.tf, valeurs d’environnement dans terraform.tfvars (ou lab.auto.tfvars), overrides ponctuels via -var / TF_VAR_.
export TF_VAR_environment=dev
terraform plan -var='bucket_prefix=deh-ci'
Étape 6 — tfvars et .gitignore des secrets
terraform.tfvars (valeurs lab, pas de secrets) :
bucket_prefix = "deh-lab"
environment = "lab"
enable_versioning = false
extra_tags = {
Owner = "devopselastichayway"
Stage = "variables-lab"
Project = "devopselastichayway"
}
terraform.tfvarset*.auto.tfvarssont chargés automatiquement à la racine du module.- Secrets : jamais commités. Exemple
.gitignore:
*.tfvars
!*.tfvars.example
*.tfvars.json
.terraform/
Versionnez un terraform.tfvars.example. Attention : sensitive masque l’affichage mais la valeur reste en clair dans le state — chiffrez le backend distant.
Étape 7 — Lab ca-central-1 : préfixe et tags
mkdir -p ~/terraform-variables-lab && cd ~/terraform-variables-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 (comme le tuto Providers).
providers.tf — region = "ca-central-1", default_tags (Project / ManagedBy / Stage), aucune clé.
variables.tf — déclarations des étapes 2–4 (bucket_prefix, environment, enable_versioning, extra_tags, bucket_config + validations).
terraform.tfvars — valeurs de l’étape 6.
main.tf :
resource "aws_s3_bucket" "lab_variables" {
# Remplacez SUFFIXE-UNIQUE (initiales + date)
bucket = "${var.bucket_prefix}-${var.environment}-SUFFIXE-UNIQUE"
force_destroy = var.bucket_config.force_destroy
tags = merge(
var.extra_tags,
{
Name = "${var.bucket_prefix}-${var.environment}"
Environment = var.environment
Purpose = var.bucket_config.purpose
}
)
}
resource "aws_s3_bucket_versioning" "lab_variables" {
bucket = aws_s3_bucket.lab_variables.id
versioning_configuration {
status = var.enable_versioning ? "Enabled" : "Suspended"
}
}
resource "aws_s3_bucket_public_access_block" "lab_variables" {
bucket = aws_s3_bucket.lab_variables.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
Attendez des + sur bucket, versioning et public access block ; vérifiez préfixe et tags dans le plan. Pas d’obligation d’apply ; si vous appliquez, enchaînez un destroy. Override : terraform plan -var='environment=dev' -var='enable_versioning=true'.
Étape 8 — Checklist
variables.tfavectype+descriptionpour chaque entrée.defaultsûr ou valeur obligatoire via tfvars / CI.sensitive = truepour secrets — ne pas les committer.validationpour préfixes, enums et plages.- Priorité : default → auto.tfvars → terraform.tfvars →
-var-file→-var/TF_VAR_. - Gitignorer
.tfvarssecrets ; versionner.tfvars.example. - Référencer
var.NOM; composer avecmerge/ interpolations. init→fmt→validate→plan; destroy si apply.
Nettoyage
Sans apply : rm -rf ~/terraform-variables-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 |
|---|---|---|
Type mismatch / Invalid value |
string là où number/bool est attendu |
Alignez le type (7 vs "7", true vs "true") |
| Variable required au plan | Pas de default ni assignation | default, tfvars, -var ou TF_VAR_ |
| Sensitive leak dans les logs | Oubli de sensitive ou output dérivé non marqué |
Marquez variable et outputs ; n’imprimez pas var.* sensible |
| Validation toujours fausse | Condition qui référence d’autres vars | Limitez à var.NOM validée |
| Mauvaise valeur « gagne » | Confusion de priorité | terraform console → var.NOM ; une seule source claire |
| Secrets dans Git | *.tfvars commités |
.gitignore + rotation |
| Bucket name invalide | Préfixe hors règles S3 | Validation regex + suffixe unique |
Quiz (3 questions)
1. Où déclare-t-on le type et la description d’une entrée ?
- A. Uniquement dans
terraform.tfvars - B. Dans un bloc
variable(souventvariables.tf) - C. Dans le bloc
provider
2. Que fait sensitive = true ?
- A. Chiffre la valeur dans le state distant
- B. Masque la valeur dans le plan / la CLI (sans chiffrer le state)
- C. Empêche toute assignation via
TF_VAR_
3. Quelle source l’emporte sur un default ?
- A. Rien — le default est toujours prioritaire
- B. Une valeur via
terraform.tfvars,-varouTF_VAR_ - C. Uniquement
.terraform.lock.hcl
Réponses : 1‑B · 2‑B · 3‑B
Pourquoi / quand introduire des variables d’entrée
Hardcoder la Region, les préfixes S3 et les tags fonctionne pour un fichier jetable. Dès que vous rejouez le lab, changez d’environnement ou partagez le module, les input variables deviennent le contrat : types, descriptions, defaults sûrs, validations, sensitive. Ce tuto pose ce contrat avant Locals et Outputs.
Quand choisir default, tfvars ou TF_VAR_
default: valeur de lab inoffensive (ex. Regionca-central-1) qui permetplansans friction.terraform.tfvars/-var-file: valeurs d’environnement versionnées sans secrets (ou fichiers gitignorés pour les secrets).-var/TF_VAR_: override CI ou one-shot local.- Pas de default : force l’appelant à choisir (utile pour un préfixe bucket unique).
Rappel de priorité (du plus faible au plus fort) : default → fichiers auto → terraform.tfvars → -var-file → -var / env. Vérifiez avec terraform console si un doute demeure.
Pièges des variables
- Types lâches (
stringpartout) : préférezbool,number,object,mappour échouer tôt. sensitive = trueoublié sur un token… ou output dérivé non marqué qui le réaffiche.- Validation qui référence d’autres variables de façon non supportée : gardez la condition locale à
var.NOM. - Commit de
secrets.tfvars:.gitignore+ exemple*.tfvars.exampleuniquement. - Validation regex S3 trop permissive : refusez majuscules et underscores tôt.
- Documenter des access keys « en variable » : non — l’auth reste profil/SSO ; TF ≥ 1.9.
Pourquoi valider tôt
Une validation claire transforme une erreur AWS obscure (BucketAlreadyExists, InvalidBucketName) en message Terraform actionnable avant l’apply. C’est du temps d’incident économisé.
Patterns utiles sans HCL supplémentaire
- Préfixe + suffixe unique (date / prénom) pour les noms globaux S3.
- Map de tags communs fusionnée (
merge) avec des tags spécifiques. - Booléen
enable_versioningpour activer un resource optionnel (avec count/for_each dans les tutos suivants). - Enum d’environnements (
dev/staging/prod) via validationcontains.
FAQ variables (étendue)
Variable vs local ? Variable = entrée externe ; local = calcul interne non surchargé par tfvars.
Puis-je changer le type après coup ? Oui mais cela casse les appels existants : versionnez le contrat (surtout en module).
Les variables apparaissent-elles dans le state ? Les valeurs résolues influencent resources/state ; les secrets sensibles restent à traiter avec précaution (remote state chiffré, pas de printf).
Faut-il une variable pour la Region ? Souvent oui, avec default ca-central-1 pour la série ; le provider consomme var.aws_region ou équivalent.
Comment documenter pour un collègue ? description obligatoire + fichier example tfvars + README du module.
Override en CI sans fichier ? TF_VAR_environment=dev dans la pipeline, combiné à -input=false.
Objets imbriqués ? object({ … }) ou map(object) : plus strict qu’un any opaque.
Sensitive et plan JSON ? Les valeurs marquées sont rédigées dans beaucoup de sorties CLI ; ne vous y fiez pas comme à un coffre-fort.
Pour aller plus loin
- Doc : Input Variables, Validation, Assigning Values
- Sur ce site : Locals, puis Outputs ; révisez Blocs HCL et Providers
- Rappel : une variable bien typée + validée évite plus d’incidents qu’un apply précipité
Maillage série Terraform (P2)
| ← Précédent | Providers et ressources (terraform-providers-ressources) |
| → Suivant | Locals (terraform-locals) |
| Aussi | Outputs (terraform-outputs) · 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.



