🏗️ HashiCorp

Terraform / IaC Mastery prompts

Prompts pour écrire, refactorer et debugger du Terraform en prod — modules, drift, revue de plan, cycles, stratégie multi-env. Prep Terraform 003.

Tested 2026-06 Claude 4.7 OpusGPT-5Gemini 2.5 Pro #terraform#iac#devops#cloud
Honest note — Ces prompts t'aident à raisonner sur ton code Terraform — ils ne remplacent pas `terraform plan`. Lis toujours le plan avant d'appliquer, et ne laisse jamais un LLM exécuter `terraform apply` ou `terraform state rm` à ta place. Le comportement des providers (aws, azurerm, google) bouge avec leurs versions majeures : précise la version de provider dans tes prompts, sinon tu obtiens du conseil obsolète.

Prompts in this set

  1. 1. Designer un module Terraform réutilisable depuis une spec
  2. 2. Comprendre pourquoi `terraform plan` veut changer quelque chose que je n'ai pas touché
  3. 3. Refactorer un main.tf monolithique en modules sans casser le state
  4. 4. Revoir un `terraform plan` avant d'appliquer en prod
  5. 5. Casser un "Cycle" ou "Error: Resource depends on itself"
  6. 6. Choisir entre workspaces, états séparés et Terragrunt

1. Designer un module Terraform réutilisable depuis une spec

Tu as besoin d'un module (VPC, EKS, RDS, App Service…) que d'autres équipes vont consommer. Tu veux une API propre, des inputs documentés, des outputs utiles et zéro couplage caché à ta région.

Claude 4.7 Opus (2026-06)GPT-5 (2026-05)
Tu es un Staff Platform Engineer qui écrit des modules Terraform consommés par 20 équipes internes. Design-moi un module pour la spec suivante.

Provider + version : <AWS_5_X|AZURERM_4_X|GOOGLE_5_X|AUTRE>
Version Terraform : <1_5+>
Nom du module : <NOM_E_G_VPC_HUB_AND_SPOKE>
Spec en clair :
<DECRIS_LA_RESSOURCE_QUE_LE_MODULE_DOIT_CRÉER>
Consommateurs attendus : <DEV_INTERNES|EQUIPES_PROD|OPEN_SOURCE>

Livre ceci, dans cet ordre :
1. **L'API publique** — la liste exacte des `variable` (nom, type, description, default, validation) et `output` (nom, value, description, sensitive si besoin). Justifie chaque variable : pourquoi elle est nécessaire, pourquoi elle n'a pas de default sûr.
2. **L'arborescence** du module — fichiers (`main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`, `README.md`, `examples/`) avec ce que chacun contient. Pas de `provider` block dans le module (anti-pattern documenté HashiCorp).
3. **Le `versions.tf`** complet avec `required_version` et `required_providers` épinglés (`~> X.Y`).
4. **Le `main.tf`** avec les ressources clés, en utilisant `for_each` plutôt que `count` partout où les éléments sont nommés, et `dynamic` blocks uniquement quand le contenu est variable (pas pour faire joli).
5. **Un exemple de consommation** dans `examples/basic/main.tf` — comment une équipe consommatrice appelle ce module sur 10-15 lignes.
6. **Les 3 décisions de design que tu n'as PAS prises** — ce que tu laisses au consommateur (VPC peering ? KMS key managée par le module ou injectée ? tags) avec un raisonnement d'une ligne par décision.

Ne me donne pas de `resource "aws_vpc" "this"` générique — utilise la spec. Si la spec est ambigüe sur un point, demande UNE clarification ciblée avant d'écrire, pas dix.
TipRègle simple pour les variables : si elle a un default sûr → default explicite. Si elle a un default qui dépend du compte/de la région → pas de default, force le consommateur à choisir. C'est ça qui empêche les modules de "marcher en dev, casser en prod".

2. Comprendre pourquoi `terraform plan` veut changer quelque chose que je n'ai pas touché

Tu lances `terraform plan`, et il t'annonce des changements que tu n'as pas demandés. Drift de state, ressource modifiée hors-Terraform, changement de provider, ou Terraform a raison et toi tort.

Claude 4.7 Opus (2026-06)GPT-5 (2026-05)Gemini 2.5 Pro (2026-05)
Mon `terraform plan` veut faire des changements que je n'ai pas demandés. Aide-moi à diagnostiquer la vraie source.

Version Terraform + provider : <E_G_TERRAFORM_1_8_AWS_5_50>
Backend de state : <S3+DYNAMODB|TFC|AZURERM|GCS|LOCAL>
Dernier apply réussi remonte à : <QUAND>
Qui d'autre a accès aux ressources / au state : <PERSONNE|PORTAL_AWS|AUTRE_PIPELINE|AUTRE_REPO>

--- extrait du plan (la ressource qui change) ---
<COLLE_LE_BLOC_PLAN_DE_LA_RESSOURCE>

--- la ressource dans le HCL ---
<COLLE_LE_BLOC_RESOURCE_HCL>

Diagnostique en suivant cet ordre — ne saute pas d'étape :
1. **Catégorie** — le diff appartient à laquelle de ces 5 boîtes : (a) drift réel (qqn a modifié la ressource hors Terraform), (b) attribut computed/optional dont le provider a changé la valeur par défaut, (c) breaking change de version de provider (depuis quand tu n'as pas bumpé `required_providers` ?), (d) attribut sensitive / no-op recalculé à chaque plan (un bug bien connu, le citer), (e) le HCL et la réalité sont d'accord mais la SOURCE est ton input qui a changé.
2. **L'évidence** — 2-3 lignes du diff qui prouvent la catégorie. Cite-les littéralement.
3. **L'action minimale** :
   - drift réel → `terraform apply` réimpose, OU `terraform import` + ajustement du HCL si le portal a raison.
   - default provider qui a bougé → ajouter l'attribut dans le HCL avec la valeur courante OU `lifecycle { ignore_changes = [...] }` ciblé (PAS sur tout le bloc).
   - breaking change provider → la note de release qui décrit le changement + comment migrer.
   - bug provider connu → numéro d'issue GitHub si tu le connais, sinon `ignore_changes` documenté en commentaire.
4. **L'anti-action** — ce qu'il ne faut PAS faire (e.g. `terraform state rm`, `taint`, ou refactor agressif tant que la catégorie n'est pas confirmée).

Ne me dis pas "il pourrait y avoir plusieurs causes". Choisis la plus probable depuis l'évidence, commit, et donne-moi l'anti-action.
TipLe drift le plus fréquent en 2026 reste les tags ajoutés par Backup / Config / SCP au niveau organisation AWS. Si tes tags changent à chaque plan et que personne ne les a touchés, regarde du côté `default_tags` sur le provider + politiques d'organisation avant de blâmer ton code.

3. Refactorer un main.tf monolithique en modules sans casser le state

Tu hérites d'un `main.tf` de 2000 lignes avec 80 ressources dans un seul fichier. Il faut le découper en modules — sans détruire et recréer les ressources prod.

Claude 4.7 Opus (2026-06)GPT-5 (2026-05)
Refactoring d'un `main.tf` monolithique vers une structure modulaire SANS détruire la prod. Aide-moi.

Version Terraform : <1_6+_pour_moved_blocks>
Nombre de ressources : <E_G_80>
Backend de state : <S3|TFC|AZURERM>
Fenêtre d'apply disponible : <PROD_LIVE_NO_DOWNTIME|MAINTENANCE_WINDOW_30M>

--- inventaire (sortie de `terraform state list`) ---
<COLLE_LA_SORTIE>

--- main.tf (ou extrait représentatif) ---
<COLLE_LE_HCL_OU_LE_PLUS_REPRESENTATIF>

Fais ceci, dans l'ordre :
1. **Groupe les ressources en 3-6 modules logiques** (réseau, calcul, données, sécurité, observabilité…). Pour chaque module, liste les ressources qu'il contiendra (adresses Terraform exactes) et 1 phrase de justification du regroupement.
2. **Choisis le mécanisme de déplacement** : `moved {}` blocks (Terraform 1.1+, ZERO downtime, à privilégier) versus `terraform state mv` (CLI, sur backend versionné seulement, riskier). Justifie le choix pour ce cas et NE mélange PAS les deux.
3. **Génère les `moved` blocks** pour TOUTES les ressources déplacées — un bloc par ressource, source = adresse actuelle, destination = nouvelle adresse module-préfixée. Aucune approximation, aucun "// etc.".
4. **L'ordre de PR** : 1 module à la fois. Pour chaque PR, le plan attendu doit être strictement `0 to add, 0 to change, 0 to destroy` avec des lignes "moved". Si une PR change un attribut, ce n'est PLUS un pur refactor — tu le signales.
5. **Le filet de sécurité avant la première PR** : (a) sauvegarder le state versionné (S3 versioning / TFC snapshot), (b) `terraform plan -out=refactor.tfplan` puis `apply refactor.tfplan` (jamais sans `-out` pour un refactor), (c) vérifier `terraform state list` post-apply = ensemble des nouvelles adresses.

Ne me propose pas de `terraform state rm` puis re-`import`. Avec `moved`, ça n'est jamais la bonne réponse pour un refactor pur en 2026.
TipSi la première PR contient plus de 20 `moved` blocks, c'est trop. Découpe en 2-3 PRs (réseau d'abord, puis calcul, puis le reste) — un humain doit pouvoir relire les `moved` un par un.

4. Revoir un `terraform plan` avant d'appliquer en prod

Le plan affiche 47 changements. Tu veux savoir lesquels sont safe, lesquels sont risqués, et lequel va tout casser à 3h du matin.

Claude 4.7 Opus (2026-06)GPT-5 (2026-05)Gemini 2.5 Pro (2026-05)
Revue de risque sur ce `terraform plan` avant un apply en prod. Sois sévère.

Environnement : <PROD|STAGING|DEV>
Provider + version : <AWS_5_X|AZURERM_4_X|GOOGLE_5_X>
Workload critique impacté : <API_PAYANTE|BATCH_INTERNE|RIEN_DE_VISIBLE>

--- terraform plan (résumé + diffs significatifs) ---
<COLLE_LE_PLAN_OU_LE_RESUME>

Range chaque changement dans EXACTEMENT une de ces 4 catégories — pas "à mi-chemin" :

🟢 **SAFE** — tag, description, attribut purement métadonnée. Aucun risque opérationnel. Pas besoin de fenêtre.

🟡 **IN-PLACE WITH BLAST RADIUS** — modifié sur place mais le service tremble (security group rule, IAM policy attachée, route table) : nommer la fenêtre courte de mauvais état pendant le change.

🟠 **REPLACE = RECREATE** — ressource recréée (`-/+`). Liste : (a) le déclencheur du replace (l'attribut ForceNew), (b) la durée d'indisponibilité attendue, (c) si une dépendance avale aussi un replace en cascade (RDS subnet group → RDS instance → app dépendante).

🔴 **DATA-LOSS** — destroy d'une ressource stateful (S3 bucket, RDS, EBS, KMS key, DynamoDB table). Souligne. Liste la protection requise (`prevent_destroy`, snapshot, deletion protection, KMS pending window).

Pour chaque ligne 🟠 et 🔴 :
1. La 1 ligne du plan qui prouve la catégorie.
2. La protection à ajouter dans le HCL AVANT d'appliquer si elle manque (`lifecycle { prevent_destroy = true }`, `deletion_protection = true`, `skip_final_snapshot = false` + `final_snapshot_identifier = ...`).
3. La séquence d'apply recommandée si le plan touche plusieurs choses (split en sous-applies, ou tout-en-un).

Finis par UN verdict en une ligne : **APPLY MAINTENANT** / **APPLY EN FENÊTRE** / **NE PAS APPLIQUER, REVOIR LE HCL D'ABORD**. Sans hedge.
TipSi le plan contient `aws_kms_key` en destroy, arrête tout. Une KMS key supprime ses données chiffrées au bout de la pending window (7-30j). Repasse en `prevent_destroy = true` + transition de clé avant de continuer.

5. Casser un "Cycle" ou "Error: Resource depends on itself"

`terraform plan` te jette une erreur de cycle de dépendances. Les ressources se référencent mutuellement et tu ne vois pas par où trancher.

Claude 4.7 Opus (2026-06)GPT-5 (2026-05)
J'ai un cycle de dépendances dans Terraform. Aide-moi à le casser proprement.

Version Terraform : <1_5+>
Provider : <AWS|AZURERM|GOOGLE>

--- message d'erreur exact ---
<COLLE_L_ERROR_MESSAGE>

--- les ressources impliquées (HCL) ---
<COLLE_LES_BLOCS_RESOURCE>

Fais ceci :
1. **Dessine le graphe** en texte ASCII : A → B → C → A, avec sur chaque flèche l'attribut qui crée la dépendance (e.g. `B.id`, `C.security_group_ids`, `A.depends_on`).
2. **Identifie l'arête fautive** — celle qu'on peut remplacer par un mécanisme qui ne crée PAS de dépendance Terraform : (a) référence à une donnée connue à l'avance (CIDR statique, nom prévisible via `name_prefix`), (b) `aws_security_group_rule` séparé au lieu de `ingress {}` inline (pattern classique SG ↔ SG), (c) attribut `lifecycle { create_before_destroy = true }` qui change l'ordre, (d) ressource intermédiaire (passerelle, alias, data source).
3. **Donne le refactor HCL** — pas la théorie, le code. Diff minimal contre le HCL fourni.
4. **Si c'est un faux cycle** introduit par un `depends_on` explicite redondant, dis-le, supprime-le, et donne le `plan` attendu sans.
5. **Si c'est un vrai cycle architectural** (les deux ressources ont VRAIMENT besoin l'une de l'autre), nomme la 3e ressource ou la convention qui résout (e.g. SG intermédiaire "shared", policy attachment séparée, ALB → target group → ECS service avec `depends_on` côté service uniquement).

Ne propose JAMAIS comme première option de fusionner deux ressources en une — c'est rarement la bonne réponse, et ça lock le state.
TipLe cycle Terraform N°1 en AWS reste : `aws_security_group A` autorise `aws_security_group B` en inline, et B autorise A en inline. Solution : sortir AU MOINS UNE des deux rules en `aws_security_group_rule` séparé. Marche dans 95% des cas.

6. Choisir entre workspaces, états séparés et Terragrunt

Tu démarres ou tu refactores une codebase multi-env (dev/staging/prod). Tu hésites entre `terraform workspace`, un dossier par env avec state séparé, ou Terragrunt.

Claude 4.7 Opus (2026-06)GPT-5 (2026-05)
Aide-moi à choisir une stratégie multi-environnement Terraform.

Nombre d'environnements : <DEV+PROD|DEV+STAGE+PROD|N_REGIONS_X_M_TENANTS>
Équipe : <SOLO|2_DEVS|10+_DEVS>
Différences entre envs : <STRICTEMENT_LES_MEMES_RESSOURCES|TAILLES_DIFFERENTES|FEATURES_DIFFERENTES>
Backend disponible : <S3+DYNAMODB|TFC|AZURERM|GCS>
Politique RBAC : <UN_SEUL_ROLE_PARTOUT|ROLES_PAR_ENV|SEPARATION_STRICTE_PROD>
Utilises-tu déjà Terragrunt ? : <OUI|NON|JAMAIS_VU>

Rends-moi un verdict à 3 colonnes :

| Critère | terraform workspace | dossier-par-env (state séparé) | Terragrunt |
|---|---|---|---|

Lignes obligatoires (pas de "divers") : isolation du state, blast radius d'un mauvais apply, DRY du code HCL, support des RBAC IAM/Azure AD par env, courbe d'apprentissage de l'équipe, dépendance externe à un outil tiers, modèle officiel HashiCorp en 2026, complexité CI/CD.

Puis :
1. **Le verdict** en une phrase pour CE contexte précis.
2. **L'arborescence concrète** que tu recommandes — fichiers et dossiers, avec ce qui vit où. Pas un readme abstrait : `live/prod/eu-west-3/network/main.tf`.
3. **Le piège n°1** de l'approche choisie + comment l'éviter (e.g. workspaces qui partagent un seul fichier de variables et finissent en `count = local.env == "prod" ? 3 : 1` partout).
4. **Ce qu'il NE FAUT PAS faire** si tu pars sur cette voie : la liste des 3 choses à interdire en revue de PR.

Note : `terraform workspace` n'est PAS la réponse par défaut pour séparer prod et dev en 2026. Si tu la recommandes, tu dois l'assumer dans le verdict.
TipSi la séparation prod/dev est une exigence de conformité (SOC 2, ISO 27001), workspaces est éliminé d'office : ils partagent un même backend, donc un même set d'IAM principals capables de lire le state. Le compliance officer ne signera pas.

How to use these prompts

Each prompt has placeholders in <ANGLE_BRACKETS> — fill them in before pasting. Copy the prompt with the button, paste into Claude, ChatGPT, Gemini, or any chat-UI'd LLM.

Why "model tested" dates matter

LLMs improve and regress with every release. A prompt that worked on Claude 3.5 may need rewriting for Claude 4. The dates show when each prompt was last verified — anything older than 6 months should be re-tested before depending on it.

Found a better prompt?

Hit contact and share — we keep prompts that beat ours.