Module 9 — Outputs : exposition, secrets et preconditions
Durée indicative du cours : 0h45
Durée indicative de l’atelier : — (atelier / démo à venir)
Durée totale (cours + atelier) : ~1h00–1h15
Objectif du module
En Basics, les outputs exposent des valeurs pour la lecture humaine et les scripts locaux.
En Associate, on traite les outputs comme un contrat : CI/CD, composition entre modules, stacks, et garde-fous (precondition) — y compris quand il faut refuser d’exposer une valeur incohérente.
On complète avec le bloc racine check pour des règles transverses (plusieurs ressources, cohérence globale).
Rappel — anatomie d’un output
output "rg_name" {
description = "Nom du resource group"
value = azurerm_resource_group.main.name
}
output "rg_id" {
description = "ID Azure du resource group"
value = azurerm_resource_group.main.id
}
| Attribut | Rôle |
|---|---|
value |
Expression exposée |
description |
Documentation humaine / terraform-docs |
sensitive |
Masque beaucoup d’affichages CLI |
precondition |
Associate — garde-fou avant publication |
Outputs sensibles
output "connection_string" {
description = "Chaîne de connexion (masquée en CLI)"
value = azurerm_storage_account.lab.primary_connection_string
sensitive = true
}
Même logique que pour les variables (module 8) :
sensitivemasque ;- le state peut toujours contenir la valeur ;
-jsonet certains outils peuvent exposer autrement — discipline d’équipe requise.
Contrat module
Si un module publie un secret en output, tous les consommateurs héritent du risque state.
Preferez souvent Key Vault + référence, ou un flux CI, plutôt qu’une chaîne en clair dans le state racine.
precondition sur un output
Bloc imbriqué dans l’output :
output "app_url" {
description = "URL HTTPS de l’application"
value = "https://${azurerm_linux_web_app.app.default_hostname}"
precondition {
condition = length(azurerm_linux_web_app.app.default_hostname) > 0
error_message = "Hostname applicatif vide — ne pas exposer d’URL."
}
}
Comportement :
- Évalué au plan / apply.
- Si
conditionestfalse, Terraform échoue avecerror_message. - L’output n’est pas « publié tranquillement » avec une valeur absurde.
Cas d’usage :
- refuser une URL vide, un ID absent, un environnement interdit ;
- garde-fou après calcul / création, côté contrat du module ;
- combiner avec
sensitive = true: masquage et refus sont des rôles différents.
Documentation : Custom Conditions · Output Values.
Ne pas confondre les garde-fous
| Mécanisme | Où | Quand ça joue | Idée |
|---|---|---|---|
variable → validation |
Entrée | Fourniture des valeurs | « mauvaise entrée » |
output → precondition |
Sortie | Plan / apply sur l’output | « mauvaise valeur à exposer » |
resource → lifecycle → precondition / postcondition |
Ressource | Avant / après la ressource | Garde-fous locaux |
Bloc check |
Racine | Plan / apply | Assertions multi-ressources (voir ci-dessous) |
resource "azurerm_resource_group" "main" {
name = local.rg_name
location = var.location
lifecycle {
precondition {
condition = var.environment != "prod" || var.force_prod
error_message = "Création prod refusée sans force_prod."
}
postcondition {
condition = self.location == var.location
error_message = "Le Resource Group n’est pas dans la région attendue."
}
}
}
precondition: évaluée avant de créer / mettre à jour la ressource.postcondition: évaluée après, sur l’état connu de la ressource (self.…).
Objectif examen TA-004 (4g) : savoir choisir le bon garde-fou (entrée / sortie / ressource / check transverse), pas seulement citer les mots-clés.
Pédagogie
validation = filtrage avant.
precondition sur output = contrôle du contrat sortant.
check = règle transversale sur l’infra déjà modélisée.
Les trois peuvent coexister dans le même projet.
Bloc check (assertions transverses)
En Basics, le panorama des blocs HCL cite check sans le dérouler. Ici, on l’utilise quand une règle concerne plusieurs ressources ou l’ensemble du déploiement, pas une seule variable ni un seul output.
Prérequis : Terraform 1.5+.
Structure
Un bloc check est un bloc racine (comme variable ou resource). Il contient un ou plusieurs sous-blocs assert :
check "storage_no_public_blob" {
assert {
condition = (
azurerm_storage_account.lab.allow_nested_items_to_be_public == false
)
error_message = "Le Storage Account autorise l’accès public : risque de fuite de données."
}
assert {
condition = azurerm_storage_account.lab.min_tls_version == "TLS1_2"
error_message = "Le Storage Account doit imposer TLS 1.2 minimum."
}
}
Chaque assert porte :
condition: expression booléenne ;error_message: message affiché si la condition est fausse.
Comportement au plan
Lors d’un terraform plan (ou apply), Terraform évalue les assert après avoir calculé le plan des ressources.
- Si une condition est fausse, Terraform signale un échec de check avec le
error_message. - Les checks servent à attraper des incohérences globales (sécurité, alignement région, tags obligatoires…) sans dupliquer la logique dans chaque
resource.
Checks vs échec bloquant
Selon la version et le contexte, un check raté peut apparaître comme diagnostic dans le plan sans toujours bloquer la suite comme une validation de variable.
Retenez surtout le rôle : assertion transversale au moment du plan.
Doc : Checks.
Exemple — cohérence entre ressources
check "same_region" {
assert {
condition = (
azurerm_resource_group.lab.location ==
azurerm_storage_account.lab.location
)
error_message = "Le Resource Group et le Storage Account doivent être dans la même région."
}
}
Utile quand plusieurs ressources sont paramétrées par des variables : le check détecte une incohérence avant de la découvrir dans le portail.
Quand choisir quoi ?
| Besoin | Mécanisme |
|---|---|
| Filtrer une valeur d’entrée | variable → validation |
| Refuser de publier un output incohérent | output → precondition |
| Garde-fou local à une ressource | lifecycle → precondition / postcondition |
| Règle sur plusieurs ressources ou l’infra globale | Bloc check |
Outputs et CI/CD
Quand : un pipeline (Azure DevOps, GitHub Actions…) déploie l’infra puis a besoin d’une valeur produite par Terraform (URL, ID, nom) pour l’étape suivante.
Pourquoi : l’output est le contrat lisible entre Terraform et le reste de la chaîne — sans parser le state à la main.
Exemple : créer l’app, puis lire l’URL pour des tests smoke.
output "app_url" {
description = "URL HTTPS de l’application"
value = "https://${azurerm_linux_web_app.app.default_hostname}"
}
Côté script / job CI :
Points à retenir :
- Préférer
-rawpour injecter une chaîne dans une variable d’environnement. - Préférer
-jsonsi l’outil attend une structure (plusieurs clés). - Un output
sensitivereste masqué en CLI, mais le secret peut vivre dans le state — discipline d’équipe (voir plus haut).
Outputs entre modules et stacks
Quand : vous composez plusieurs modules (réseau, app, données) dans un même projet, ou plusieurs stacks (projets Terraform séparés).
Pourquoi : le module enfant expose ce dont le parent a besoin (vnet_id, subnet_ids) sans dupliquer la logique Azure.
Dans un module enfant (modules/network) :
output "vnet_id" {
description = "ID du Virtual Network"
value = azurerm_virtual_network.main.id
}
output "vnet_name" {
description = "Nom du Virtual Network"
value = azurerm_virtual_network.main.name
}
Dans le module parent (racine) :
module "network" {
source = "./modules/network"
}
resource "azurerm_subnet" "app" {
# ...
virtual_network_name = module.network.vnet_name
}
Le parent lit module.network.<output>. C’est la base de la composition de modules.
Variante avec map d’IDs :
# Dans modules/network/outputs.tf
output "subnet_ids" {
value = { for k, s in azurerm_subnet.this : k => s.id }
}
# Racine
module "app" {
source = "./modules/app"
subnet_id = module.network.subnet_ids["app"]
}
Cross-stack (plusieurs projets / states) : terraform_remote_state ou publication via Terraform Cloud — le contrat (noms d’outputs stables) compte autant que la technique. Ce sujet sera détaillé avec les backends distants.
Lien Basics
En Terraform Basics, les outputs restent sur un seul projet (lecture humaine, script local). Les cas CI/CD et inter-modules vivent ici.
Parcours démo / atelier (cible)
- Output simple sans
precondition(rappel Basics). - Ajouter une
preconditionqui échoue → lire le message. - Corriger →
planOK ;terraform output/-json. - Option : même idée en
lifecycle.preconditionsur une ressource pour contraster. - Option : ajouter un bloc
check(ex. même région RG / storage) et lire le diagnostic au plan.
À enrichir
Exemple fil rouge plateforme (output réseau consommé par app) ; pièges -raw vs -json avec sensitive.
Suite
Poursuivre avec le module 10 — Configuration avancée.
Théorie suivante : count / for_each, fonctions HCL, dynamic, provisioners et self.