Aller au contenu
Variables, sorties et valeurs locales

Variables, sorties et valeurs locales

200 Pratiquer ⏱ 1 h 10 terraformopentofuhcl

À la fin, vous saurez

  • Déclarer des variables d'entrée typées, documentées et validées
  • Prédire quelle valeur une variable reçoit quand plusieurs sources la définissent
  • Exposer des résultats par des sorties, et les lire depuis un script
  • Factoriser des expressions avec des valeurs locales
  • Décrire la préproduction et la production avec la même configuration et deux fichiers de valeurs
  • Expliquer ce que sensitive cache, ce qu'il ne cache pas, et quand une valeur éphémère est nécessaire

Prérequis

Testé avec local 2.9.1 random 3.9.1 scaleway 2.84.0 terraform 1.16.1 , vérifié le 5 octobre 2026

Pourquoi

À la fin de la leçon précédente, la configuration de Signalements fonctionnait, mais elle était écrite pour un seul cas. Le nom du bucket, signalements-pj-exemple, y figurait en dur, comme la plage 172.16.20.0/22, la zone, les étiquettes. L'équipe a pourtant deux environnements, la préproduction et la production, qui doivent se ressembler comme deux gouttes d'eau, à la taille près : une instance en préproduction, trois en production.

Sans paramètres, il n'y a que deux façons de faire, et elles sont mauvaises toutes les deux :

  • copier le répertoire et modifier la copie : au bout de trois mois, les deux configurations ont divergé, une correction appliquée à l'une n'a jamais été reportée dans l'autre, et la préproduction ne teste plus ce qui part en production ;
  • modifier le code avant chaque application, selon l'environnement visé : une modification oubliée, et l'on applique en production la taille de la préproduction.

Kief Morris, dans Infrastructure as Code, en fait un principe : une même définition de l'infrastructure, appliquée à plusieurs environnements avec des paramètres différents, et seulement des paramètres. Les variables d'entrée sont ces paramètres ; les sorties en sont l'inverse, ce que la configuration rend au monde ; les valeurs locales évitent de répéter une expression. Cette leçon pose les trois, puis s'arrête sur une question de sécurité que les variables soulèvent tôt ou tard : que devient un mot de passe passé en variable ?

Les concepts

Les variables d'entrée

Une variable d'entrée se déclare par un bloc variable, et se lit partout ailleurs par var.<nom>. Ses arguments, tous facultatifs :

ArgumentRôle
typeLa contrainte de type : string, number, bool, list(string), map(string), set(...), object({...}), tuple([...]), ou any
descriptionCe que la variable représente ; affichée quand Terraform la demande, et lue par les outils de documentation
defaultLa valeur si personne n'en fournit ; sans default, la variable est obligatoire
validationUne ou plusieurs règles, avec une condition et un message d'erreur
sensitiveMasque la valeur dans l'affichage des plans et des sorties
ephemeralInterdit à la valeur d'être enregistrée dans l'état ou le plan (depuis Terraform 1.10 et OpenTofu 1.11)
nullableSi false, refuse la valeur null et lui substitue le default

Le type est la première protection : une variable number refuse "trois", une list(string) refuse une table. Les types structurés décrivent un objet complet, avec des attributs facultatifs et leurs valeurs par défaut (optional(type, défaut)) :

variable "instances" {
  type = object({
    type  = string
    zones = optional(list(string), ["fr-par-1", "fr-par-2"])
  })
  description = "Gabarit des instances applicatives."
  default     = { type = "PRO2-XXS" }
}

La validation va plus loin que le type : elle exprime une règle métier. Sa condition est une expression booléenne qui peut faire référence à la variable elle-même ; si elle est fausse, le plan s'arrête avec le message choisi. Écrivez ce message comme une phrase qui dit quoi corriger.

D'où viennent les valeurs

Une variable peut recevoir sa valeur de six endroits. Quand plusieurs la définissent, la documentation de Terraform fixe l'ordre, du plus fort au plus faible :

  1. les options -var et -var-file de la ligne de commande, dans l'ordre où elles sont écrites (la dernière l'emporte) ;
  2. les fichiers *.auto.tfvars et *.auto.tfvars.json, dans l'ordre alphabétique de leur nom ;
  3. le fichier terraform.tfvars.json ;
  4. le fichier terraform.tfvars ;
  5. les variables d'environnement TF_VAR_<nom> ;
  6. le default du bloc variable.

Deux conséquences. Les fichiers terraform.tfvars et *.auto.tfvars sont lus automatiquement, sans rien demander : un tel fichier oublié dans le répertoire change silencieusement les valeurs. Et les variables d'environnement sont les plus faibles des sources explicites : un TF_VAR_ exporté dans votre terminal est battu par n'importe quel fichier de valeurs. La pratique le confirme plus bas.

Si une variable obligatoire n'a de valeur nulle part, Terraform la demande de façon interactive, ou échoue avec -input=false, ce que doit toujours faire un pipeline.

Les sorties

Une sortie (output value) se déclare par un bloc output et expose une valeur calculée : le nom généré du bucket, l'adresse du répartiteur, l'identifiant du réseau privé. Elle sert à trois choses : afficher un résultat à la fin d'un apply, le rendre lisible par un script (terraform output -json), et, dans un module, le transmettre à la configuration qui l'appelle (cours avancé).

Une sortie accepte description, sensitive, ephemeral (pour les modules enfants), depends_on (rarement utile : quand la valeur exposée ne doit être considérée prête qu'après une ressource dont elle ne dépend pas par référence) et un bloc precondition, qui vérifie une condition avant d'exposer la valeur.

Les valeurs locales

Une valeur locale se déclare dans un bloc locals et se lit par local.<nom>. C'est un nom donné à une expression, pour ne l'écrire qu'une fois : le préfixe sig-preprod, la table des étiquettes communes, la liste des noms d'instances. Une valeur locale n'est pas un paramètre : on ne peut pas la changer de l'extérieur.

La règle d'usage : une variable pour ce qui change d'un environnement à l'autre ou d'une utilisation à l'autre ; une locale pour ce qui se calcule à partir des variables ; une valeur en dur pour ce qui ne doit changer nulle part. Trop de variables rendent une configuration impossible à relire (« qu'est-ce qui est réellement paramétrable ? ») ; trop peu obligent à copier.

Sensible et éphémère

sensitive = true sur une variable ou une sortie fait afficher (sensitive value) à la place de la valeur dans les plans, et <sensitive> dans la liste des sorties. Le caractère sensible se propage : une expression qui utilise une valeur sensible est sensible, et une sortie de la configuration racine qui en contient une doit être déclarée sensitive, sinon Terraform refuse le plan.

Mais sensitive ne fait que masquer l'affichage. La documentation des sorties est explicite : Terraform enregistre les valeurs des sorties sensibles dans l'état, et terraform output avec -json ou -raw les affiche en clair. Il en va de même des variables sensibles utilisées par des ressources : elles sont dans l'état, en clair, comme le montre la leçon 6.

Pour qu'une valeur ne soit jamais écrite, Terraform 1.10 a introduit les valeurs éphémères (ephemeral = true), reprises par OpenTofu 1.11 : la valeur existe pendant l'opération, puis disparaît ; elle n'est enregistrée ni dans le plan, ni dans l'état. En contrepartie, elle ne peut aller que là où rien n'est enregistré : une configuration de fournisseur, une autre valeur éphémère, et les arguments en écriture seule (write-only, depuis Terraform 1.11) que certaines ressources proposent. Le fournisseur Scaleway en a plusieurs : password_wo sur scaleway_rdb_instance, scaleway_rdb_user ou scaleway_redis_cluster, data_wo sur scaleway_secret_version.

En pratique

On travaille dans un répertoire d'essai, avec les fournisseurs random et local : rien n'est créé dans le cloud, mais tout le mécanisme est réel. Les sorties ont été produites avec Terraform 1.16.1.

Déclarer les variables

Fichier variables.tf :

variable "environnement" {
  type        = string
  description = "Nom de l'environnement : preprod ou prod."

  validation {
    condition     = contains(["preprod", "prod"], var.environnement)
    error_message = "L'environnement doit valoir preprod ou prod."
  }
}

variable "nombre_instances" {
  type        = number
  description = "Nombre d'instances applicatives."
  default     = 2

  validation {
    condition     = var.nombre_instances >= 1 && var.nombre_instances <= 6
    error_message = "Entre 1 et 6 instances."
  }
}

variable "etiquettes" {
  type        = map(string)
  description = "Étiquettes ajoutées à toutes les ressources."
  default     = {}
}

variable "jeton_notifications" {
  type        = string
  description = "Jeton d'accès au service de notifications."
  sensitive   = true
}

environnement et jeton_notifications n'ont pas de default : elles sont obligatoires. La limite de six instances n'est pas technique : c'est une garde contre une faute de frappe (60 au lieu de 6) qui coûterait cher.

Les valeurs locales et les ressources

Fichier main.tf (le bloc terraform avec random et local est omis) :

locals {
  prefixe = "sig-${var.environnement}"
  etiquettes = merge(
    { app = "signalements", env = var.environnement, geree-par = "terraform" },
    var.etiquettes,
  )
  noms_instances = [for i in range(var.nombre_instances) : "${local.prefixe}-app-${i + 1}"]
}

resource "random_pet" "suffixe_bucket" {
  length = 2
}

resource "local_file" "inventaire" {
  filename = "${path.module}/inventaire-${var.environnement}.txt"
  content  = join("\n", concat(local.noms_instances, [""]))
}

resource "local_sensitive_file" "jeton" {
  filename        = "${path.module}/jeton-${var.environnement}.txt"
  content         = var.jeton_notifications
  file_permission = "0600"
}
  • merge combine deux tables, la seconde l'emportant : les étiquettes communes, puis celles de l'environnement.
  • [for i in range(...) : ...] est une expression for qui fabrique une liste ; la leçon 9 les détaille.
  • random_pet fabrique un suffixe lisible pour le nom du bucket, qui doit être unique dans la région ; il sera tiré une fois, puis conservé dans l'état.

Les sorties

Fichier outputs.tf :

output "bucket" {
  description = "Nom du bucket des pièces jointes."
  value       = "signalements-pj-${random_pet.suffixe_bucket.id}"
}

output "noms_instances" {
  value = local.noms_instances
}

output "etiquettes" {
  value = local.etiquettes
}

output "jeton" {
  value     = var.jeton_notifications
  sensitive = true
}

Une validation qui échoue

$ terraform plan -no-color -var environnement=production -var jeton_notifications=x
...
Error: Invalid value for variable

  on variables.tf line 1:
   1: variable "environnement" {
    ├────────────────
    │ var.environnement is "production"

L'environnement doit valoir preprod ou prod.

This was checked by the validation rule at variables.tf:5,3-13.

Le message cite la valeur reçue, le message que vous avez écrit, et l'emplacement de la règle. Terraform 1.16 affiche d'ailleurs, juste avant, la partie du plan qu'il a pu calculer (la création du random_pet, qui ne dépend pas de la variable), sous l'en-tête Terraform planned the following actions, but then encountered a problem : ce n'est pas un plan applicable, la commande sort avec le code 1.

Sans le jeton, avec -input=false comme en CI :

$ terraform plan -no-color -input=false -var environnement=prod
Error: No value for required variable

  on variables.tf line 28:
  28: variable "jeton_notifications" {

The root module input variable "jeton_notifications" is not set, and has no
default value. Use a -var or -var-file command line argument to provide a
value for this variable.

Un fichier de valeurs par environnement

Fichier preprod.tfvars :

environnement    = "preprod"
nombre_instances = 1
etiquettes = {
  equipe = "signalements"
}

Fichier prod.tfvars :

environnement    = "prod"
nombre_instances = 3
etiquettes = {
  equipe    = "signalements"
  criticite = "haute"
}

Le jeton n'y figure pas : un fichier de valeurs est versionné, un secret ne l'est jamais. Il arrive par l'environnement :

$ export TF_VAR_jeton_notifications='jeton-de-demo-123'
$ terraform apply -no-color -auto-approve -var-file=preprod.tfvars
...
  # local_sensitive_file.jeton will be created
  + resource "local_sensitive_file" "jeton" {
      + content              = (sensitive value)
      ...
      + file_permission      = "0600"
      + filename             = "./jeton-preprod.txt"
      + id                   = (known after apply)
    }
...
Plan: 3 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + bucket         = (known after apply)
  + etiquettes     = {
      + app       = "signalements"
      + env       = "preprod"
      + equipe    = "signalements"
      + geree-par = "terraform"
    }
  + jeton          = (sensitive value)
  + noms_instances = [
      + "sig-preprod-app-1",
    ]
...
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

bucket = "signalements-pj-working-urchin"
etiquettes = {
  "app" = "signalements"
  "env" = "preprod"
  "equipe" = "signalements"
  "geree-par" = "terraform"
}
jeton = <sensitive>
noms_instances = [
  "sig-preprod-app-1",
]

La ressource local_sensitive_file déclare elle-même son contenu comme sensible ; la sortie jeton est masquée parce qu'elle porte sensitive = true.

Lire les sorties depuis un script

$ terraform output -json noms_instances
["sig-preprod-app-1"]
$ terraform output jeton
"jeton-de-demo-123"
$ terraform output -raw jeton
jeton-de-demo-123

-json donne une valeur exploitable par jq ; -raw donne une chaîne sans guillemets, pratique dans un script shell. Et la valeur sensible s'affiche en clair dès qu'on la demande par son nom. Le masquage protège d'un regard par-dessus l'épaule ou d'un journal de CI, pas de quelqu'un qui a accès au répertoire et à l'état.

Qui l'emporte ?

Testons l'ordre de priorité. Le fichier preprod.tfvars fixe nombre_instances = 1. Une variable d'environnement en demande cinq :

$ TF_VAR_nombre_instances=5 terraform plan -no-color -var-file=preprod.tfvars
...
No changes. Your infrastructure matches the configuration.

Le fichier passé par -var-file l'emporte : toujours une instance, rien ne change. Ajoutons maintenant un fichier ajustement.auto.tfvars qui contient nombre_instances = 2, et planifions sans -var-file, la variable d'environnement toujours à cinq :

$ TF_VAR_nombre_instances=5 terraform plan -no-color -var environnement=preprod
...
Plan: 1 to add, 0 to change, 1 to destroy.

Changes to Outputs:
  ~ etiquettes     = {
      - equipe    = "signalements"
        # (3 unchanged attributes hidden)
    }
  ~ noms_instances = [
        "sig-preprod-app-1",
      + "sig-preprod-app-2",
    ]

Deux instances : le fichier *.auto.tfvars, lu sans qu'on le demande, a battu la variable d'environnement. Et l'étiquette equipe disparaît, puisque preprod.tfvars n'est plus lu. Le plan montre aussi que l'inventaire serait remplacé (1 to add, 1 to destroy) : changer le contenu d'un local_file impose de recréer le fichier, comme changer certains arguments d'une ressource cloud impose de la recréer (leçon 8). Supprimez ajustement.auto.tfvars : l'expérience est terminée.

Interroger la configuration avec la console

terraform console évalue une expression dans le contexte de la configuration et de l'état, sans rien modifier. C'est l'outil pour mettre au point une expression :

$ echo 'local.noms_instances' | terraform console -var-file=prod.tfvars
[
  "sig-prod-app-1",
  "sig-prod-app-2",
  "sig-prod-app-3",
]
$ echo 'var.instances' | terraform console -var-file=prod.tfvars
{
  "type" = "PRO2-XXS"
  "zones" = tolist([
    "fr-par-1",
    "fr-par-2",
  ])
}
$ echo 'var.jeton_notifications' | terraform console -var-file=prod.tfvars
(sensitive value)

Le deuxième résultat montre l'attribut facultatif zones, absent du default, complété par sa valeur par défaut. Le troisième montre que la console masque elle aussi les valeurs sensibles.

Une sortie sensible oubliée

Retirez sensitive = true de la sortie jeton, et planifiez :

$ terraform plan -no-color -var-file=preprod.tfvars
Error: Output refers to sensitive values

  on outputs.tf line 14:
  14: output "jeton" {

To reduce the risk of accidentally exporting sensitive data that was intended
to be only internal, Terraform requires that any root module output
containing sensitive data be explicitly marked as sensitive, to confirm your
intent.

Terraform refuse : une valeur sensible ne devient pas publique par accident. Remettez l'argument.

Une valeur éphémère

Pour le mot de passe initial de la base sig-db, sensitive ne suffit pas : il finirait dans l'état. Déclarons-le éphémère :

variable "mot_de_passe_base" {
  type        = string
  description = "Mot de passe initial de la base, fourni au moment de l'application."
  sensitive   = true
  ephemeral   = true
}

Essayons de l'écrire dans un fichier par local_file, dont l'argument content est enregistré dans l'état :

$ terraform validate -no-color
Error: Invalid use of ephemeral value

  with local_file.fuite,
  on essai_ephemere.tf line 3, in resource "local_file" "fuite":
   3:   content  = var.mot_de_passe_base

Ephemeral values are not valid for "content", because it is not a write-only
attribute and must be persisted to state.

Le refus vient dès la validation : une valeur éphémère ne peut aller que dans un argument en écriture seule. Avec le fournisseur Scaleway, la base de la leçon 10 recevra donc son mot de passe par password_wo :

resource "scaleway_rdb_instance" "base" {
  name                = "sig-db"
  node_type           = "DB-DEV-S"
  engine              = "PostgreSQL-16"
  user_name           = "signalements"
  password_wo         = var.mot_de_passe_base
  password_wo_version = 1
  project_id          = data.scaleway_account_project.signalements.id
}

terraform validate accepte ce bloc avec le fournisseur 2.84 ; c'est le plan qui dira si le type de nœud et la version du moteur existent.

password_wo_version est le seul moyen de dire au fournisseur que le mot de passe a changé : Terraform ne garde aucune trace de la valeur, il ne peut donc pas comparer. On incrémente ce numéro à chaque rotation. (La version du moteur et le type de nœud sont à choisir d'après scw rdb engine list et scw rdb node-type list, comme au cours cloud.)

Nettoyez le répertoire d'essai par terraform destroy -var-file=preprod.tfvars.

Sous le capot

L'évaluation. Les variables, les locales et les sorties sont des nœuds du graphe des dépendances, comme les ressources (leçon 8). Une variable est connue avant le plan ; une locale ou une sortie est évaluée dès que les valeurs dont elle dépend sont connues. Une sortie qui dépend d'un attribut calculé reste (known after apply) au plan.

Le marquage. Le caractère sensible n'est pas une propriété du texte, mais une marque attachée à la valeur pendant l'évaluation. Chaque fonction, chaque concaténation propage la marque au résultat. Elle est enregistrée dans l'état sous la forme d'une liste sensitive_attributes (leçon 6), pour que les plans suivants continuent de masquer ; la valeur elle-même y est en clair. Le caractère éphémère est une autre marque, que Terraform vérifie avant d'écrire quoi que ce soit : une valeur ainsi marquée ne peut atteindre aucun champ enregistré.

Les fichiers de valeurs. Un fichier .tfvars n'est pas du HCL complet : il ne contient que des affectations de valeurs littérales, sans référence ni fonction. Un fichier .tfvars.json contient un objet JSON, pratique quand un autre programme le génère.

Différence avec OpenTofu. OpenTofu a ajouté en version 1.8 la possibilité d'utiliser des variables et des locales dans la configuration du stockage de l'état et dans les adresses de modules, avec des limites (les valeurs doivent être connues avant tout plan). Terraform ne le permet pas : la configuration du stockage de l'état ne lit pas les variables, et la leçon 7 montre comment la paramétrer autrement.

Pièges courants

Un terraform.tfvars ou un *.auto.tfvars oublié. Il est lu sans rien demander et l'emporte sur l'environnement. Préférez des fichiers nommés par environnement, passés explicitement par -var-file, et regardez ls *.tfvars avant un plan qui surprend.

Une validation qui ne valide que le type. type = string accepte "prd", "Prod", "production". Si seules deux valeurs ont un sens, dites-le avec contains.

Croire que sensitive protège le secret. Il masque l'affichage, pas l'état ni terraform output -raw. La leçon 6 montre le mot de passe en clair dans le fichier d'état.

Un secret dans un fichier de valeurs versionné. prod.tfvars finit dans Git, puis dans tous les clones. Les secrets passent par l'environnement en CI, et mieux encore par des valeurs éphémères ou un gestionnaire de secrets (cours Gestion des secrets).

Paramétrer tout. Une configuration à quarante variables, dont trente ne changent jamais, se relit mal et cache les vraies différences entre environnements. Commencez en dur, transformez en variable quand un second usage le demande.

Les guillemets dans le shell. -var 'etiquettes={equipe="sig"}' demande des guillemets simples autour de l'ensemble, faute de quoi le shell mange les guillemets intérieurs. Les fichiers de valeurs évitent ce piège.

Compter sur les espaces de travail pour séparer les environnements. Voir En production.

Sécurité

  • Les secrets n'ont rien à faire dans le code ni dans les fichiers de valeurs versionnés. Variables d'environnement TF_VAR_ injectées par les secrets de la CI, ou lecture depuis un gestionnaire de secrets.
  • sensitive est un masque d'affichage. Il évite qu'un jeton apparaisse dans les journaux d'un pipeline public, ce qui est déjà beaucoup. Il ne remplace pas la protection de l'état (leçons 6 et 7).
  • ephemeral et les arguments en écriture seule sont la seule façon de passer un secret à une ressource sans qu'il soit écrit dans l'état. Ils demandent Terraform 1.11 ou OpenTofu 1.11, et un fournisseur qui propose l'argument ; vérifiez dans son schéma.
  • Les variables d'environnement ne sont pas secrètes pour tout le monde. Le cours Linux l'a montré : /proc/<pid>/environ est lisible par le même utilisateur et par root. Sur un agent de CI partagé, c'est un risque à connaître.
  • Les validations sont aussi des garde-fous de sécurité : refuser une plage 0.0.0.0/0 dans une variable de règle de pare-feu, ou un nombre d'instances absurde, évite des erreurs coûteuses avant qu'elles n'atteignent le plan.

En production

  • Un environnement, une configuration racine (ou un répertoire), un état. La documentation des espaces de travail (workspaces) de la CLI le dit sans détour : quand les déploiements ont des identifiants et des contrôles d'accès différents, comme une préproduction et une production, les espaces de travail d'un même répertoire partagent le même stockage d'état, et ne sont donc pas un mécanisme d'isolation adapté. La leçon 7 met en place un état par environnement, chacun dans son projet Scaleway.
  • Les fichiers de valeurs portent les seules différences entre environnements. Si prod.tfvars et preprod.tfvars diffèrent sur trente lignes, la préproduction ne teste plus la production.
  • Des noms et des étiquettes dérivés de l'environnement (sig-prod-app-1, env = prod) rendent les ressources reconnaissables dans la console et dans la facture (cours cloud, leçon 8).
  • Les sorties forment le contrat de la configuration avec le reste du monde : le pipeline de déploiement lit l'adresse du répartiteur, le registre lit l'espace de noms. Documentez-les avec description, et changez-les avec la même prudence qu'une API.
  • Un pipeline n'est jamais interactif : -input=false partout, pour qu'une variable manquante fasse échouer le job au lieu de l'attendre indéfiniment.

Exercices

1. Prédire une valeur (niveau 100). Une variable zone a pour default "fr-par-1". Le fichier terraform.tfvars contient zone = "fr-par-2", la variable d'environnement TF_VAR_zone vaut "fr-par-3", et la commande est terraform plan -var-file=prod.tfvars, où prod.tfvars ne parle pas de zone. Quelle zone sera utilisée ? Et si l'on ajoute -var zone=nl-ams-1 ?

Solution

fr-par-2 : prod.tfvars ne définit pas zone, le fichier terraform.tfvars est lu automatiquement et l'emporte sur l'environnement et sur le default. Avec -var zone=nl-ams-1, c'est nl-ams-1 : les options de la ligne de commande sont les plus fortes.

2. Une validation utile (niveau 200). Écrivez une variable plage_reseau_prive (type string, valeur par défaut 172.16.20.0/22) dont la validation refuse ce qui n'est pas un bloc CIDR valide, et ce qui n'est pas dans les plages privées 172.16.0.0/12 ou 10.0.0.0/8. Indice : les fonctions can, cidrhost et cidrsubnet, ou la comparaison de cidrhost(var.x, 0).

Solution

Une solution, vérifiée avec Terraform 1.16 sur 172.16.20.0/22 et 10.4.0.0/16 (acceptés), 192.168.1.0/24, 172.32.0.0/16 et pasuncidr (refusés) :

variable "plage_reseau_prive" {
  type    = string
  default = "172.16.20.0/22"

  validation {
    condition     = can(cidrhost(var.plage_reseau_prive, 0))
    error_message = "La plage doit être un bloc CIDR IPv4 valide, par exemple 172.16.20.0/22."
  }

  validation {
    condition = try(anytrue([
      for parent in ["172.16.0.0/12", "10.0.0.0/8"] :
      tonumber(split("/", var.plage_reseau_prive)[1]) >= tonumber(split("/", parent)[1])
      && cidrhost("${cidrhost(var.plage_reseau_prive, 0)}/${split("/", parent)[1]}", 0) == cidrhost(parent, 0)
    ]), false)
    error_message = "La plage doit appartenir à 172.16.0.0/12 ou à 10.0.0.0/8."
  }
}

La seconde règle vérifie, pour chaque bloc parent, que le préfixe demandé est au moins aussi long, et que l'adresse de réseau, tronquée à la longueur du parent, est celle du parent. can transforme une erreur en false ; try(..., false) fait de même pour la seconde règle, qui sinon échouerait avec une erreur d'index sur une valeur qui n'est pas un bloc CIDR. Les deux messages s'affichent alors pour pasuncidr. Mettez au point ce genre d'expression dans terraform console avant de l'écrire dans une validation.

3. Sensible ou éphémère (niveau 200). Pour chaque valeur, dites si elle doit être une variable ordinaire, sensible, ou éphémère, et pourquoi : (a) le type d'instance ; (b) le jeton d'API d'un service de notifications, que l'application lit dans Secret Manager, et que Terraform doit déposer dans un secret Scaleway ; (c) le mot de passe initial de la base ; (d) l'adresse e-mail de l'astreinte.

Solution

(a) Ordinaire. (b) Éphémère, transmise à l'argument en écriture seule data_wo de scaleway_secret_version : le jeton n'est alors ni dans le plan ni dans l'état. (c) Éphémère, transmise à password_wo de scaleway_rdb_instance, avec password_wo_version incrémenté à chaque rotation. (d) Ordinaire : une donnée personnelle n'est pas un secret ; la marquer sensible compliquerait la lecture des plans sans rien protéger (elle serait de toute façon dans l'état).

4. Deux environnements (niveau 200). Avec la configuration de la pratique, appliquez successivement preprod.tfvars puis prod.tfvars dans le même répertoire. Que fait le second apply aux fichiers créés par le premier ? Qu'en concluez-vous pour l'organisation des environnements ?

Solution

Il les remplace : l'état ne connaît qu'un local_file.inventaire, dont le nom de fichier passe de inventaire-preprod.txt à inventaire-prod.txt ; Terraform détruit le premier et crée le second (et de même pour le jeton). Avec des ressources cloud, appliquer la production par-dessus la préproduction détruirait la préproduction. Un état par environnement est indispensable : un répertoire ou une configuration de stockage par environnement (leçon 7).

Récapitulatif

  • Une variable d'entrée (var.x) est un paramètre : type, description, valeur par défaut, validation ; sans default, elle est obligatoire.
  • Ordre de priorité, du plus fort au plus faible : -var et -var-file, *.auto.tfvars, terraform.tfvars.json, terraform.tfvars, TF_VAR_, default. Les fichiers automatiques sont lus sans qu'on le demande.
  • Une sortie expose un résultat ; terraform output -json ou -raw la lit depuis un script.
  • Une valeur locale (local.x) nomme une expression calculée.
  • Une configuration, plusieurs fichiers de valeurs : les environnements ne diffèrent que par leurs paramètres, et chacun a son propre état.
  • sensitive masque l'affichage, mais la valeur reste en clair dans l'état. ephemeral (Terraform 1.10, OpenTofu 1.11) et les arguments en écriture seule (password_wo) l'en tiennent dehors.

Pour aller plus loin

  • Les pages Input variables et Manage sensitive data de la documentation de Terraform.
  • Le chapitre de Kief Morris sur la configuration des environnements, qui discute les différentes façons de fournir des paramètres à une pile d'infrastructure.
  • La leçon suivante, qui ouvre le fichier d'état et y retrouve, en clair, ce que sensitive cachait.
Voir ma constellation →

Sources