
27 exercices pratiques qui simulent le format lab. Chaque exercice pose un problème concret : écrire du HCL, corriger une erreur, refactorer du code. Les solutions sont masquées — essayez de résoudre chaque exercice avant de regarder la réponse.
Objectif 1 — Manage resource lifecycle
Section intitulée « Objectif 1 — Manage resource lifecycle »Exercice 1 — Importer une ressource existante (déclaratif)
Section intitulée « Exercice 1 — Importer une ressource existante (déclaratif) »Situation : Un collègue a créé un bucket S3 manuellement (my-app-logs-prod). Vous devez l’intégrer dans le code Terraform sans recréer le bucket.
Consigne : Écrivez le bloc import {} et la ressource correspondante pour que terraform plan ne montre aucun changement.
Voir la solution
import { to = aws_s3_bucket.logs id = "my-app-logs-prod"}
resource "aws_s3_bucket" "logs" { bucket = "my-app-logs-prod"}Vérification :
terraform plan# Plan: 1 to import, 0 to add, 0 to change, 0 to destroy
terraform apply# aws_s3_bucket.logs: Importing... [id=my-app-logs-prod]# Import complete!
terraform plan# No changes. Your infrastructure matches the configuration.# 0 to add, 0 to change, 0 to destroyLe plan prépare l’import, mais seul l’apply l’exécute réellement. Si le plan après l’apply montre des changements, c’est que la ressource HCL ne correspond pas à l’état réel. Ajoutez les attributs manquants (tags, versioning, etc.) pour éliminer le diff.
Exercice 2 — Refactorer avec moved
Section intitulée « Exercice 2 — Refactorer avec moved »Situation : Votre configuration contient aws_instance.web_server. Vous voulez la déplacer dans un module compute sous le nom aws_instance.main, sans détruire l’instance.
Consigne : Écrivez le bloc moved {} et l’appel de module nécessaires.
Voir la solution
# Dans le root modulemoved { from = aws_instance.web_server to = module.compute.aws_instance.main}
module "compute" { source = "./modules/compute"
ami = var.ami_id instance_type = var.instance_type subnet_id = var.subnet_id}# Dans modules/compute/main.tfresource "aws_instance" "main" { ami = var.ami instance_type = var.instance_type subnet_id = var.subnet_id}Vérification :
terraform plan# Doit afficher :# aws_instance.web_server has moved to module.compute.aws_instance.main# 0 to add, 0 to change, 0 to destroySi le plan montre un destroy + create, le bloc moved est mal formé ou les attributs de la ressource dans le module ne correspondent pas.
Exercice 3 — Manipulation du state
Section intitulée « Exercice 3 — Manipulation du state »Situation : Votre state contient une ressource aws_iam_role.legacy qui a été supprimée manuellement dans la console AWS. terraform plan veut la recréer. Vous avez déjà retiré le bloc resource correspondant du code.
Consigne : Quelle commande permet de supprimer l’entrée orpheline du state ?
Voir la solution
# Retirer du state sans tenter de détruire dans AWSterraform state rm aws_iam_role.legacy
# Vérifier que la ressource n'est plus dans le stateterraform state list | grep legacy
# Le plan doit maintenant être propreterraform plan# 0 to add, 0 to change, 0 to destroyNe confondez pas state rm (retire du state uniquement) avec destroy (supprime dans AWS + retire du state). Ici, la ressource n’existe plus dans AWS : on nettoie le state.
Attention : state rm ne retire l’objet que du state. Si le bloc resource est toujours présent dans le code, le plan suivant tentera de recréer la ressource. Il faut donc retirer le bloc HCL et nettoyer le state.
Exercice 4 — Forcer la recréation
Section intitulée « Exercice 4 — Forcer la recréation »Situation : L’AMI de votre instance aws_instance.web a été corrompue. L’instance tourne encore mais vous devez la recréer à partir de la même AMI.
Consigne : Quelle commande force la recréation sans modifier le code HCL ?
Voir la solution
# Forcer la destruction + recréationterraform apply -replace=aws_instance.webLe plan affichera :
# aws_instance.web must be replaced-/+ resource "aws_instance" "web" {L’ancienne syntaxe terraform taint est dépréciée depuis Terraform 0.15.2. Utilisez toujours -replace.
Exercice 5 — Détection de drift
Section intitulée « Exercice 5 — Détection de drift »Situation : Un administrateur a modifié les tags d’une instance directement dans la console AWS. Vous voulez détecter les changements sans appliquer aucune modification.
Consigne : Quelle commande permet de mettre à jour le state avec l’état réel sans modifier l’infrastructure ?
Voir la solution
# Détecter le drift : met à jour le state avec l'état réel AWSterraform plan -refresh-only
# Appliquer la mise à jour du state (sans modifier l'infra)terraform apply -refresh-onlyAprès apply -refresh-only, le state reflète l’état réel. Un terraform plan normal montrera ensuite les différences entre le code HCL et le nouvel état du state — c’est-à-dire les modifications manuelles à corriger ou à adopter.
Objectif 2 — Dynamic configuration
Section intitulée « Objectif 2 — Dynamic configuration »Exercice 6 — Precondition sur une variable
Section intitulée « Exercice 6 — Precondition sur une variable »Situation : Vous créez un module qui accepte un instance_type. Le module ne supporte que les types t3.* et t2.*.
Consigne : Ajoutez une precondition qui bloque le plan si un type non supporté est passé.
Voir la solution
variable "instance_type" { type = string}
resource "aws_instance" "main" { ami = var.ami_id instance_type = var.instance_type
lifecycle { precondition { condition = can(regex("^t[23]\\.", var.instance_type)) error_message = "Seuls les types t2.* et t3.* sont supportés. Reçu : ${var.instance_type}" } }}Avec instance_type = "m5.large", le plan échoue avec :
│ Error: Resource precondition failed││ Seuls les types t2.* et t3.* sont supportés. Reçu : m5.largeExercice 7 — Dynamic block
Section intitulée « Exercice 7 — Dynamic block »Situation : Vous avez une variable ports de type list(number) contenant les ports à ouvrir. Créez un security group avec un bloc dynamic pour les règles ingress.
Consigne : Écrivez le security group avec un dynamic block qui crée une règle ingress TCP par port.
Voir la solution
variable "ports" { type = list(number) default = [80, 443, 8080]}
resource "aws_security_group" "web" { name = "web-sg" description = "Security group pour le web" vpc_id = var.vpc_id
dynamic "ingress" { for_each = var.ports content { from_port = ingress.value to_port = ingress.value protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } }
egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] }}Le bloc dynamic itère sur var.ports. L’itérateur par défaut porte le nom du bloc (ingress). Pour un nom personnalisé, ajoutez iterator = ....
Exercice 8 — terraform test
Section intitulée « Exercice 8 — terraform test »Situation : Vous avez un module qui crée un bucket S3 avec le naming pattern {env}-{app}-data. Écrivez un test qui :
- Vérifie que le bucket est créé
- Vérifie que le nom suit le pattern attendu
Consigne : Écrivez le fichier .tftest.hcl complet.
Voir la solution
variables { environment = "test" app_name = "myapp"}
run "create_bucket" { command = plan
assert { condition = aws_s3_bucket.data.bucket == "test-myapp-data" error_message = "Le nom du bucket ne suit pas le pattern {env}-{app}-data. Obtenu : ${aws_s3_bucket.data.bucket}" }
assert { condition = aws_s3_bucket.data.bucket != "" error_message = "Le bucket ne doit pas avoir un nom vide." }}Le module correspondant :
resource "aws_s3_bucket" "data" { bucket = "${var.environment}-${var.app_name}-data"}terraform test# Success! 2 passed, 0 failed.Exercice 9 — Check block (vérification post-apply)
Section intitulée « Exercice 9 — Check block (vérification post-apply) »Situation : Après le déploiement d’un load balancer, vous voulez vérifier que l’endpoint /health répond en 200.
Consigne : Écrivez un bloc check qui vérifie la santé du load balancer.
Voir la solution
resource "aws_lb" "main" { name = "app-lb" internal = false load_balancer_type = "application" subnets = var.public_subnet_ids}
check "lb_health" { data "http" "health" { url = "http://${aws_lb.main.dns_name}/health" }
assert { condition = data.http.health.status_code == 200 error_message = "Le load balancer ne répond pas sur /health (code: ${data.http.health.status_code})." }}Le bloc check est évalué en fin de plan et en fin d’apply. Contrairement aux postconditions, un échec de check n’annule pas l’opération — il émet un warning. C’est un mécanisme de surveillance continue, pas de validation bloquante.
Exercice 10 — Postcondition
Section intitulée « Exercice 10 — Postcondition »Situation : Vous créez une instance EC2 qui doit obtenir une IP publique. Si l’instance est lancée dans un sous-réseau privé par erreur, vous voulez que Terraform échoue.
Consigne : Ajoutez une postcondition qui vérifie que l’instance a reçu une IP publique.
Voir la solution
resource "aws_instance" "web" { ami = var.ami_id instance_type = var.instance_type subnet_id = var.subnet_id associate_public_ip_address = true
lifecycle { postcondition { condition = self.public_ip != "" error_message = "L'instance n'a pas reçu d'IP publique. Vérifiez que le sous-réseau ${var.subnet_id} est public." } }}La postcondition s’évalue après la création de la ressource. Si l’instance est créée sans IP publique, Terraform marque l’opération comme échouée et bloque les actions downstream qui dépendent de cette ressource — mais il ne rollback pas ce qui a déjà été créé. L’instance existera dans le state, avec une erreur à corriger.
Exercice 11 — Fonctions avancées : flatten
Section intitulée « Exercice 11 — Fonctions avancées : flatten »Situation : Vous avez une variable qui définit des environnements avec chacun une liste de sous-réseaux :
variable "environments" { default = { prod = { subnets = ["10.0.1.0/24", "10.0.2.0/24"] } dev = { subnets = ["10.1.1.0/24"] } }}Consigne : Utilisez flatten et une boucle for pour créer une liste plate de tous les sous-réseaux avec leur environnement.
Voir la solution
locals { all_subnets = flatten([ for env, config in var.environments : [ for cidr in config.subnets : { environment = env cidr = cidr } ] ])}
# Résultat :# [# { environment = "prod", cidr = "10.0.1.0/24" },# { environment = "prod", cidr = "10.0.2.0/24" },# { environment = "dev", cidr = "10.1.1.0/24" },# ]
# Utilisation avec for_each (nécessite une map ou un set)resource "aws_subnet" "all" { for_each = { for s in local.all_subnets : "${s.environment}-${s.cidr}" => s }
vpc_id = var.vpc_id cidr_block = each.value.cidr
tags = { Environment = each.value.environment }}Le pattern flatten + double for + conversion en map avec for_each est très fréquent dans l’examen.
Objectif 3 — Collaborative workflows
Section intitulée « Objectif 3 — Collaborative workflows »Exercice 12 — Backend S3 + DynamoDB
Section intitulée « Exercice 12 — Backend S3 + DynamoDB »Situation : Vous devez configurer un backend distant S3 avec verrouillage DynamoDB pour une infrastructure de production.
Consigne : Écrivez la configuration complète du backend et la table DynamoDB.
Voir la solution
terraform { backend "s3" { bucket = "mycompany-terraform-state" key = "production/network/terraform.tfstate" region = "eu-west-1" dynamodb_table = "terraform-locks" encrypt = true }}# state-infra/main.tf (à appliquer séparément, avec un backend local)resource "aws_s3_bucket" "state" { bucket = "mycompany-terraform-state"}
resource "aws_s3_bucket_versioning" "state" { bucket = aws_s3_bucket.state.id versioning_configuration { status = "Enabled" }}
resource "aws_dynamodb_table" "locks" { name = "terraform-locks" billing_mode = "PAY_PER_REQUEST" hash_key = "LockID"
attribute { name = "LockID" type = "S" }}La table DynamoDB doit avoir une clé primaire nommée LockID de type String. C’est un piège fréquent dans l’examen.
Note 2026 : le backend S3 supporte désormais le verrouillage natif via use_lockfile = true, rendant la table DynamoDB dépréciée. L’exercice conserve DynamoDB car l’examen Professional cible Terraform 1.6, où ce mécanisme est encore la norme.
Exercice 13 — terraform_remote_state
Section intitulée « Exercice 13 — terraform_remote_state »Situation : L’équipe réseau a déployé un VPC avec Terraform. Ses outputs exposent vpc_id et private_subnet_ids. Vous devez lire ces outputs pour déployer vos instances.
Consigne : Écrivez le data source terraform_remote_state et utilisez les outputs.
Voir la solution
data "terraform_remote_state" "network" { backend = "s3" config = { bucket = "mycompany-terraform-state" key = "production/network/terraform.tfstate" region = "eu-west-1" }}
resource "aws_instance" "app" { count = 2
ami = var.ami_id instance_type = "t3.medium" subnet_id = data.terraform_remote_state.network.outputs.private_subnet_ids[count.index] vpc_security_group_ids = [aws_security_group.app.id]
tags = { Name = "app-${count.index}" }}
resource "aws_security_group" "app" { vpc_id = data.terraform_remote_state.network.outputs.vpc_id
ingress { from_port = 8080 to_port = 8080 protocol = "tcp" cidr_blocks = ["10.0.0.0/16"] }}L’accès aux outputs se fait via data.terraform_remote_state.<name>.outputs.<key>. Les outputs du VPC doivent être déclarés dans la configuration réseau avec output "vpc_id" { ... } et output "private_subnet_ids" { ... }.
Exercice 14 — Version constraints
Section intitulée « Exercice 14 — Version constraints »Situation : Votre équipe utilise le provider AWS 5.x. Vous devez empêcher toute mise à jour vers une version 6.x non testée, tout en permettant les mises à jour mineures.
Consigne : Écrivez la contrainte de version correcte.
Voir la solution
terraform { required_version = ">= 1.6.0"
required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } }}~> 5.0 signifie : >= 5.0.0 et < 6.0.0. C’est l’opérateur pessimistic constraint — il autorise les mises à jour de la partie la plus à droite seulement.
| Contrainte | Autorise | Bloque |
|---|---|---|
~> 5.0 | >= 5.0.0, < 6.0.0 | 6.0.0+ |
~> 5.30 | >= 5.30.0, < 6.0.0 | 6.0.0+ |
~> 5.30.0 | >= 5.30.0, < 5.31.0 | 5.31.0+ |
>= 5.0, < 5.50 | 5.0.0 → 5.49.x | 5.50.0+ |
La différence clé : ~> 5.30 a deux composants (majeur.mineur) donc le mineur peut incrémenter librement sous la même majeure ; ~> 5.30.0 a trois composants donc seul le patch peut incrémenter.
Objectif 4 — Modules
Section intitulée « Objectif 4 — Modules »Exercice 15 — Passer un provider à un module
Section intitulée « Exercice 15 — Passer un provider à un module »Situation : Vous gérez une infrastructure multi-région. Votre module compute doit être déployé dans eu-west-1 et us-east-1.
Consigne : Écrivez les deux appels de module avec le bon provider pour chaque région.
Voir la solution
provider "aws" { region = "eu-west-1"}
provider "aws" { alias = "us_east" region = "us-east-1"}
# main.tfmodule "eu_compute" { source = "./modules/compute"
providers = { aws = aws }
instance_type = "t3.medium" environment = "production"}
module "us_compute" { source = "./modules/compute"
providers = { aws = aws.us_east }
instance_type = "t3.medium" environment = "production"}terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } }}Le provider par défaut (sans alias) n’a pas besoin de providers = {} dans l’appel de module. L’attribut providers est requis uniquement quand vous passez un provider avec alias.
Exercice 16 — Refactoring : count vers for_each
Section intitulée « Exercice 16 — Refactoring : count vers for_each »Situation : Votre code utilise count pour créer 3 instances. Quand vous supprimez l’instance du milieu, Terraform veut recréer les instances restantes.
variable "names" { default = ["web-1", "web-2", "web-3"]}
resource "aws_instance" "app" { count = length(var.names) ami = var.ami_id instance_type = "t3.micro" tags = { Name = var.names[count.index] }}Consigne : Convertissez en for_each et écrivez les blocs moved nécessaires.
Voir la solution
variable "names" { default = ["web-1", "web-2", "web-3"]}
resource "aws_instance" "app" { for_each = toset(var.names) ami = var.ami_id instance_type = "t3.micro" tags = { Name = each.key }}
# Bloc moved pour chaque instance existantemoved { from = aws_instance.app[0] to = aws_instance.app["web-1"]}
moved { from = aws_instance.app[1] to = aws_instance.app["web-2"]}
moved { from = aws_instance.app[2] to = aws_instance.app["web-3"]}Avec for_each, supprimer "web-2" de la liste ne touche que cette instance. C’est l’avantage principal de for_each sur count — les clés sont stables.
Exercice 17 — Module avec outputs imbriqués
Section intitulée « Exercice 17 — Module avec outputs imbriqués »Situation : Votre module network crée un VPC et 3 sous-réseaux privés. Le root module a besoin du VPC ID et de la liste des subnet IDs.
Consigne : Écrivez les outputs du module et leur utilisation dans le root module.
Voir la solution
output "vpc_id" { description = "ID du VPC créé" value = aws_vpc.main.id}
output "private_subnet_ids" { description = "Liste des IDs de sous-réseaux privés" value = [for s in aws_subnet.private : s.id]}
output "private_subnet_cidrs" { description = "Map subnet name → CIDR" value = { for k, s in aws_subnet.private : k => s.cidr_block }}# root main.tfmodule "network" { source = "./modules/network"
vpc_cidr = "10.0.0.0/16" subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]}
resource "aws_instance" "app" { count = 3 subnet_id = module.network.private_subnet_ids[count.index]
tags = { VPC = module.network.vpc_id }}Les outputs de module sont accessibles via module.<name>.<output_name>. Si l’output contient des données sensibles, ajoutez sensitive = true.
Objectif 5 — Providers
Section intitulée « Objectif 5 — Providers »Exercice 18 — Provider aliasing pour un certificat ACM
Section intitulée « Exercice 18 — Provider aliasing pour un certificat ACM »Situation : Votre application est déployée en eu-west-1, mais les certificats ACM pour CloudFront doivent être créés dans us-east-1.
Consigne : Configurez les providers et créez le certificat dans la bonne région.
Voir la solution
provider "aws" { region = "eu-west-1"}
provider "aws" { alias = "us_east" region = "us-east-1"}
resource "aws_acm_certificate" "cdn" { provider = aws.us_east domain_name = "app.example.com" validation_method = "DNS"
lifecycle { create_before_destroy = true }}
resource "aws_cloudfront_distribution" "main" { # Utilise le provider par défaut (eu-west-1) # Le certificat ACM doit être dans us-east-1 pour CloudFront
viewer_certificate { acm_certificate_arn = aws_acm_certificate.cdn.arn ssl_support_method = "sni-only" }}C’est un pattern classique de l’examen : CloudFront exige un certificat ACM dans us-east-1, quel que soit la région de déploiement.
Exercice 19 — Assume role cross-account
Section intitulée « Exercice 19 — Assume role cross-account »Situation : Vous déployez de l’infrastructure dans un compte AWS cible depuis votre compte de management. Le rôle arn:aws:iam::TARGET_ACCOUNT:role/TerraformRole est disponible.
Consigne : Configurez le provider pour assumer ce rôle.
Voir la solution
provider "aws" { region = "eu-west-1"
assume_role { role_arn = "arn:aws:iam::123456789012:role/TerraformRole" session_name = "terraform-deploy" external_id = "terraform-2026" }}Terraform utilise les credentials locales (ou du CI/CD) pour faire un sts:AssumeRole vers le compte cible. Le external_id est optionnel mais recommandé pour la sécurité cross-account.
Vérification :
# Avant l'assume roleaws sts get-caller-identity
# Terraform assume le rôle automatiquement lors du plan/applyterraform planExercice 20 — Debug provider
Section intitulée « Exercice 20 — Debug provider »Situation : terraform plan échoue avec une erreur cryptique :
Error: error configuring Terraform AWS Provider: failed to get shared config profileConsigne : Décrivez les étapes de diagnostic dans l’ordre.
Voir la solution
# 1. Vérifier les credentials actuellesaws sts get-caller-identity
# 2. Vérifier la configuration du providercat main.tf | grep -A 10 'provider "aws"'
# 3. Vérifier les variables d'environnementenv | grep AWS
# 4. Vérifier le profil référencécat ~/.aws/configcat ~/.aws/credentials
# 5. Activer les logs détaillésexport TF_LOG=DEBUGterraform plan 2>&1 | grep -i "profile\|credential\|auth"
# 6. Tester avec des credentials explicitesexport AWS_ACCESS_KEY_ID="..."export AWS_SECRET_ACCESS_KEY="..."terraform planL’erreur “failed to get shared config profile” signifie que le provider référence un profil (profile = "xxx") qui n’existe pas dans ~/.aws/config ou ~/.aws/credentials. Soit le profil est mal nommé, soit le fichier credentials n’est pas au bon endroit.
Objectif 6 — HCP Terraform (QCM)
Section intitulée « Objectif 6 — HCP Terraform (QCM) »Exercice 21 — Modes d’exécution HCP Terraform
Section intitulée « Exercice 21 — Modes d’exécution HCP Terraform »Question : Dans HCP Terraform, quel mode d’exécution permet de lancer terraform plan et terraform apply sur votre machine locale tout en stockant le state dans HCP ?
A. Remote execution B. Local execution C. Agent execution D. CLI-driven execution
Voir la réponse
B. Local execution
HCP Terraform propose trois modes d’exécution (execution modes) :
| Mode d’exécution | Plan/Apply | State | Usage |
|---|---|---|---|
| Remote | HCP | HCP | Défaut, CI/CD |
| Local | Machine locale | HCP | Développement |
| Agent | Agent auto-hébergé | HCP | Réseau privé |
CLI-driven n’est pas un mode d’exécution — c’est un workflow qui déclenche un run remote depuis la CLI locale (le plan/apply s’exécute sur HCP, pas en local).
Attention : en mode Local, HCP Terraform n’évalue pas les workspace variables ni les variable sets. Seules les variables définies localement (.tfvars, env, CLI) sont prises en compte.
Exercice 22 — Sentinel et Policy-as-Code
Section intitulée « Exercice 22 — Sentinel et Policy-as-Code »Question : À quel moment Sentinel évalue-t-il les policies dans le workflow HCP Terraform ?
A. Avant le plan B. Après le plan, avant l’apply C. Après l’apply D. Au commit Git
Voir la réponse
B. Après le plan, avant l’apply
Le workflow HCP Terraform est :
- Plan — Terraform génère le plan d’exécution
- Policy check — Sentinel évalue les policies sur le plan
- Apply — Si les policies passent, l’apply est autorisé
Les policies Sentinel peuvent avoir trois niveaux :
advisory— Warning seulementsoft-mandatory— Bloquant, mais un admin peut forcerhard-mandatory— Bloquant, pas de dérogation
Exercice 23 — Variable sets
Section intitulée « Exercice 23 — Variable sets »Question : Vous avez 15 workspaces qui partagent les mêmes credentials AWS. Comment les distribuer efficacement sans dupliquer les variables ?
A. Définir les variables dans chaque workspace
B. Utiliser un fichier .tfvars partagé
C. Créer un variable set attaché aux workspaces
D. Utiliser des environment variables sur le runner
Voir la réponse
C. Créer un variable set attaché aux workspaces
Les variable sets de HCP Terraform permettent de :
- Définir des variables une seule fois
- Les partager entre plusieurs workspaces ou un projet entier
- Gérer les credentials de manière centralisée
- Supporter les variables sensibles (valeur masquée)
Les réponses A et D fonctionnent mais ne sont pas efficaces à l’échelle. La réponse B n’est pas supportée nativement par HCP Terraform.
Exercice 24 — Workspace VCS workflow
Section intitulée « Exercice 24 — Workspace VCS workflow »Question : Dans un workspace HCP Terraform configuré avec un VCS workflow, que se passe-t-il quand un pull request est ouvert ?
A. Un terraform apply est exécuté automatiquement
B. Un speculative plan est exécuté et un check de statut est posté sur la PR
C. Rien, il faut lancer un run manuellement
D. Le workspace est verrouillé
Voir la réponse
B. Un speculative plan est exécuté et un check de statut est posté sur la PR
Le VCS workflow de HCP Terraform :
- PR ouverte → Speculative plan (plan-only, non applicable). HCP poste un status check (et un lien vers le plan) sur la pull request.
- Merge sur la branche par défaut → Full run (plan + apply après approbation)
C’est le workflow recommandé pour les équipes : le plan en PR permet la revue de code et la revue d’infrastructure en même temps. Le status check permet de voir directement si le plan passe ou échoue, sans quitter l’interface VCS.
Exercice 25 — Run triggers
Section intitulée « Exercice 25 — Run triggers »Question : Le workspace network produit des outputs (VPC ID, subnet IDs) consommés par le workspace compute via terraform_remote_state. Comment déclencher automatiquement un run de compute quand network change ?
A. Webhook personnalisé B. Run trigger de network vers compute C. Variable set partagé D. API Terraform
Voir la réponse
B. Run trigger de network vers compute
Les run triggers créent une chaîne de dépendances entre workspaces. Quand le workspace source (network) termine un apply avec succès, un run est automatiquement déclenché dans le workspace destination (compute).
Configuration : dans le workspace compute, ajouter network comme source de run trigger. C’est une relation one-to-many : un workspace peut avoir plusieurs sources.
Exercice 26 — Dependency lock file
Section intitulée « Exercice 26 — Dependency lock file »Question : Après un terraform init, le fichier .terraform.lock.hcl est créé. Quel est son rôle et que se passe-t-il si vous supprimez ce fichier puis relancez terraform init ?
A. Rien — Terraform réinstalle les mêmes versions B. Terraform installe la dernière version compatible (qui peut différer) C. Terraform refuse de s’initialiser D. Le state est corrompu
Voir la réponse
B. Terraform installe la dernière version compatible (qui peut différer)
Le fichier .terraform.lock.hcl (dependency lock file) enregistre les versions exactes et les hashes de chaque provider installé. Il garantit que toute l’équipe utilise exactement les mêmes binaires de providers.
Si vous le supprimez, terraform init résout de nouveau les contraintes de version et peut installer une version plus récente (si ~> 5.0 autorise 5.80 alors que le lock plaçait 5.72, par exemple).
Bonnes pratiques :
- Committer
.terraform.lock.hcldans le répertoire Git - Utiliser
terraform init -upgradepour mettre à jour volontairement les providers - Ne jamais le mettre dans
.gitignore
Exercice 27 — Partage de données entre workspaces HCP
Section intitulée « Exercice 27 — Partage de données entre workspaces HCP »Question : Dans HCP Terraform, vous voulez que le workspace app consomme le vpc_id produit par le workspace network. Quelle méthode est recommandée par HCP Terraform pour éviter d’exposer l’intégralité du state ?
A. terraform_remote_state avec un backend S3
B. Le data source tfe_outputs
C. Une variable set partagée
D. Un webhook d’API
Voir la réponse
B. Le data source tfe_outputs
data "tfe_outputs" "network" { organization = "myorg" workspace = "network"}
resource "aws_instance" "app" { subnet_id = data.tfe_outputs.network.values.private_subnet_ids[0]}tfe_outputs est le data source recommandé par HCP Terraform pour le partage inter-workspaces. Contrairement à terraform_remote_state, il n’expose que les outputs (pas l’intégralité du state), et il respecte les permissions RBAC du workspace source.
| Méthode | Accès | Sécurité | Usage |
|---|---|---|---|
terraform_remote_state | State complet | Faible | Legacy, backend S3 |
tfe_outputs | Outputs uniquement | RBAC | Recommandé HCP |
| Variable set | Valeurs statiques | Admin | Credentials partagées |
Grille de scoring
Section intitulée « Grille de scoring »Notez vos résultats par objectif :
| Objectif | Exercices | Réussis | Score |
|---|---|---|---|
| 1 — Resource lifecycle | 1 à 5 | _ / 5 | _ % |
| 2 — Dynamic configuration | 6 à 11 | _ / 6 | _ % |
| 3 — Collaborative workflows | 12 à 14, 26 | _ / 4 | _ % |
| 4 — Modules | 15 à 17 | _ / 3 | _ % |
| 5 — Providers | 18 à 20 | _ / 3 | _ % |
| 6 — HCP Terraform (QCM) | 21 à 25, 27 | _ / 6 | _ % |
| Total | 27 | _ / 27 | _ % |
Interprétation
Section intitulée « Interprétation »| Score | Niveau | Action |
|---|---|---|
| 90 %+ | Prêt pour l’examen | Planifiez votre date |
| 75 – 89 % | Presque prêt | Renforcez les objectifs faibles |
| 60 – 74 % | En progression | Reprenez les commandes et refaites les exercices |
| < 60 % | Insuffisant | Revoyez les guides de préparation avant de réessayer |
À retenir
Section intitulée « À retenir »- L’examen lab exige de la vitesse — connaître les commandes par coeur fait la différence
moved {}etimport {}(déclaratifs) sont préférés aux commandes CLI équivalentes- Le pattern
flatten+for+for_eachest omniprésent dans les labs - Les preconditions/postconditions et check blocks sont des sujets récents et fréquents
- Le provider aliasing multi-région (ACM + CloudFront) est un classique
terraform testavec les fichiers.tftest.hclest un sujet clé depuis Terraform 1.6- Le fichier
.terraform.lock.hcldoit être committé — il garantit des versions de providers identiques pour toute l’équipe - En HCP Terraform,
tfe_outputsest préféré àterraform_remote_statepour le partage inter-workspaces - L’objectif 6 teste vos connaissances théoriques sur HCP — pas de pratique lab