<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>TerraformAssociate on Valérian Pyckaert</title>
        <link>https://valerian-pyckaert.dev/tags/terraformassociate/</link>
        <description>Recent content in TerraformAssociate on Valérian Pyckaert</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>fr-FR</language>
        <lastBuildDate>Thu, 03 Sep 2026 14:58:35 +0200</lastBuildDate><atom:link href="https://valerian-pyckaert.dev/tags/terraformassociate/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Terraform Associate #9 — Certifié !</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-certification/</link>
            <pubDate>Thu, 03 Sep 2026 14:58:35 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-certification/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-certification/image.png&#34; alt=&#34;Featured image of post Terraform Associate #9 — Certifié !&#34; /&gt;&lt;p&gt;C&amp;rsquo;est fait : j&amp;rsquo;ai obtenu la certification &lt;a class=&#34;link&#34; href=&#34;https://www.hashicorp.com/en/certification/terraform-associate&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;HashiCorp Certified: Terraform Associate&lt;/a&gt; aujourd&amp;rsquo;hui, au terme de la série d&amp;rsquo;articles commencée avec &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/certification-terraform-associate/&#34; &gt;l&amp;rsquo;objectif certification&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;lexamen&#34;&gt;&lt;a href=&#34;#lexamen&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;L&amp;rsquo;examen&#xA;&lt;/h2&gt;&lt;p&gt;Pas de mauvaise surprise sur le fond : les sujets couverts correspondaient à ce que j&amp;rsquo;avais préparé au fil des huit précédents articles, suivant l&amp;rsquo;exam guide point par point. Le seul vrai piège, ce sont certaines tournures de questions volontairement ambiguës, qui font douter même quand on connaît la réponse. Il faut prendre le temps de bien relire l&amp;rsquo;énoncé avant de répondre.&lt;/p&gt;&#xA;&lt;h2 id=&#34;ce-qui-a-le-plus-aidé&#34;&gt;&lt;a href=&#34;#ce-qui-a-le-plus-aid%c3%a9&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce qui a le plus aidé&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Écrire les articles au fil de l&amp;rsquo;eau.&lt;/strong&gt; Reformuler chaque module avec mes propres mots a forcé la clarification de ce que je pensais déjà maîtriser, et a fait ressortir les zones floues.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;La mise en pratique sur un cas concret&lt;/strong&gt; (&lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/&#34; &gt;hub &amp;amp; spoke sur GCP&lt;/a&gt;) plutôt que des exemples jetables : ça ancre les concepts (state, modules, workspaces) bien mieux que la lecture seule.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Les questions type examen&lt;/strong&gt;, pour se confronter au format réel et repérer les points faibles avant le jour J.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;la-suite&#34;&gt;&lt;a href=&#34;#la-suite&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;La suite&#xA;&lt;/h2&gt;&lt;p&gt;Direction la certification Google Professional Cloud Architect (PCA), pour élargir cette base Terraform à une vision plus large de l&amp;rsquo;architecture cloud sur GCP.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #8 — Mise en pratique : hub &amp; spoke sur GCP</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/</link>
            <pubDate>Mon, 31 Aug 2026 11:08:24 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/index.png&#34; alt=&#34;Featured image of post Terraform Associate #8 — Mise en pratique : hub &amp; spoke sur GCP&#34; /&gt;&lt;p&gt;Après les sept premiers modules de ma préparation à la certification &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt; (fondamentaux, IaC, workflow, configuration, modules, state,&amp;hellip;), place à la pratique : je mets ces connaissances en application en construisant une architecture réseau &lt;strong&gt;hub &amp;amp; spoke&lt;/strong&gt; sur GCP.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;&lt;a href=&#34;#introduction&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Introduction&#xA;&lt;/h2&gt;&lt;p&gt;Une architecture hub &amp;amp; spoke, c&amp;rsquo;est comme un aéroport de correspondance : un &lt;strong&gt;hub&lt;/strong&gt; central qui concentre les ressources et services partagés, et des &lt;strong&gt;spokes&lt;/strong&gt; qui y sont raccordés mais qui n&amp;rsquo;ont pas de liaison directe entre eux. Tout le trafic transite par le hub.&lt;/p&gt;&#xA;&lt;p&gt;Appliqué à un réseau cloud, ça donne :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;un &lt;strong&gt;hub&lt;/strong&gt; : un VPC central qui héberge les ressources partagées (passerelle NAT, connectivité vers l&amp;rsquo;extérieur, éventuellement pare-feu et DNS centralisés) ;&lt;/li&gt;&#xA;&lt;li&gt;des &lt;strong&gt;spokes&lt;/strong&gt; : des VPC isolés par environnement, ici &lt;strong&gt;dev&lt;/strong&gt; et &lt;strong&gt;prod&lt;/strong&gt;, connectés au hub mais étanches l&amp;rsquo;un par rapport à l&amp;rsquo;autre.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;L&amp;rsquo;intérêt : mutualiser ce qui peut l&amp;rsquo;être tout en gardant une isolation forte entre environnements, un cas d&amp;rsquo;usage classique pour tester en conditions réelles les notions vues dans les articles précédents (modules, state, workflow).&lt;/p&gt;&#xA;&lt;p&gt;À la fin de ce tutoriel, vous saurez construire cette architecture sur GCP avec Terraform.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prérequis&#34;&gt;&lt;a href=&#34;#pr%c3%a9requis&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Prérequis&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;Avoir suivi les articles précédents de la série &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt;, notamment sur les &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-modules/&#34; &gt;modules&lt;/a&gt; et le &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-state-management/&#34; &gt;state&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Un compte GCP avec un projet.&lt;/li&gt;&#xA;&lt;li&gt;Terraform installé et le CLI &lt;code&gt;gcloud&lt;/code&gt; configuré.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;architecture&#34;&gt;&lt;a href=&#34;#architecture&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Architecture&#xA;&lt;/h2&gt;&lt;p&gt;Voici l&amp;rsquo;architecture visée :&lt;/p&gt;&#xA;&lt;pre class=&#34;mermaid&#34; style=&#34;visibility:hidden&#34;&gt;graph TB&#xA;    subgraph HUB[&#34;hub-vpc — 10.0.0.0/24&#34;]&#xA;        HubSub[&#34;hub-subnet&#34;]&#xA;        HubVM[&#34;hub-vm&#34;]&#xA;        HubSub --- HubVM&#xA;    end&#xA;&#xA;    subgraph DEV[&#34;spoke-dev-vpc — 10.1.0.0/24&#34;]&#xA;        DevSub[&#34;spoke-dev-subnet&#34;]&#xA;        DevVM[&#34;spoke-dev-vm&#34;]&#xA;        DevNAT[&#34;Cloud Router + Cloud NAT&#34;]&#xA;        DevSub --- DevVM&#xA;        DevSub --- DevNAT&#xA;    end&#xA;&#xA;    subgraph PROD[&#34;spoke-prod-vpc — 10.2.0.0/24&#34;]&#xA;        ProdSub[&#34;spoke-prod-subnet&#34;]&#xA;        ProdVM[&#34;spoke-prod-vm&#34;]&#xA;        ProdNAT[&#34;Cloud Router + Cloud NAT&#34;]&#xA;        ProdSub --- ProdVM&#xA;        ProdSub --- ProdNAT&#xA;    end&#xA;&#xA;    DEV &lt;--&gt;|VPC Peering| HUB&#xA;    PROD &lt;--&gt;|VPC Peering| HUB&#xA;    DevNAT --&gt; Internet((&#34;Internet&#34;))&#xA;    ProdNAT --&gt; Internet&lt;/pre&gt;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;VPC&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Subnet&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;CIDR&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;hub-vpc&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;hub-subnet&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;10.0.0.0/24&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;spoke-dev-vpc&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;spoke-dev-subnet&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;10.1.0.0/24&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;spoke-prod-vpc&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;spoke-prod-subnet&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;10.2.0.0/24&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Chaque spoke aura un peering bidirectionnel avec le hub (&lt;code&gt;hub_to_spoke&lt;/code&gt; / &lt;code&gt;spoke_to_hub&lt;/code&gt;); aucun peering entre les différent spoke, pas de NAT ni IP publique pour les VM.&lt;/p&gt;&#xA;&lt;h2 id=&#34;iterations&#34;&gt;&lt;a href=&#34;#iterations&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Iterations&#xA;&lt;/h2&gt;&lt;h3 id=&#34;1-mise-en-place-de-linfrastructure-de-base&#34;&gt;&lt;a href=&#34;#1-mise-en-place-de-linfrastructure-de-base&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;1. Mise en place de l&amp;rsquo;infrastructure de base&#xA;&lt;/h3&gt;&lt;p&gt;Ici l&amp;rsquo;idée a été de partir d&amp;rsquo;une configuration simple en laissant volontairement des pistes d&amp;rsquo;améliorations.&#xA;On part d&amp;rsquo;une configuration qui fonctionne et petit à petit on vise quelque chose d&amp;rsquo;optimisé et portable entreprise.&lt;/p&gt;&#xA;&lt;p&gt;Voici l&amp;rsquo;architecture obtenue :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── .gitignore&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── .terraform.lock.hcl&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── README.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── compute.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── firewall.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── main.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── peering.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── routing.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── subnet.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── variables.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── vpc.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Une structure plate, un fichier par type de ressource (VPC, subnet, firewall, peering, routing, compute), le tout dans un seul state local.&lt;/p&gt;&#xA;&lt;p&gt;La totalité de la configuration est disponible &lt;a class=&#34;link&#34; href=&#34;https://github.com/Bernedotcom2312/gcp-hub-and-spoke/tree/92863ed90f6668db77b6570eb3350549dfca32b2&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;ici&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;2-refactoring-à-laide-de-modules&#34;&gt;&lt;a href=&#34;#2-refactoring-%c3%a0-laide-de-modules&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;2. Refactoring à l&amp;rsquo;aide de modules&#xA;&lt;/h3&gt;&lt;p&gt;Si on analyse la configuration précédente, on voit rapidement que pas mal de configuration est dupliquée :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;google_compute_instance&amp;#34; &amp;#34;hub_vm&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hub-vm&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  machine_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;e2-micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  zone&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;europe-west1-b&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;boot_disk&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;initialize_params&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;debian-cloud/debian-13&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;network_interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    network&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;google_compute_network&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;hub&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    subnetwork&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;google_compute_subnetwork&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;hub&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;    # pas de access_config =&amp;gt; pas d&amp;#39;IP publique&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;google_compute_instance&amp;#34; &amp;#34;spoke_vm&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  for_each&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;spokes&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${each.key}-vm&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  machine_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;e2-micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  zone&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;europe-west1-b&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;boot_disk&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;initialize_params&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;debian-cloud/debian-13&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;network_interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    network&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;google_compute_network&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;spoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    subnetwork&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;google_compute_subnetwork&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;spoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Créons donc un module &lt;strong&gt;compute&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;google_compute_instance&amp;#34; &amp;#34;this&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.name}-vm&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  machine_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.machine_type}&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  zone&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;europe-west1-b&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;boot_disk&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;initialize_params&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;debian-cloud/debian-13&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;network_interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    network&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;network_interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;network&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    subnetwork&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;network_interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;subnetwork&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;variables.tf&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Nom logique de la machine&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;machine_type&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Type de la machine&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  default&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;e2-micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;network_interface&amp;#34;&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    type&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      network&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      subnetwork&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;outputs.tf&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;compute_id&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;google_compute_instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;network_name&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;google_compute_instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans notre module root il suffit alors d&amp;rsquo;appeler ce module via :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hub_vm&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;./modules/compute&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hub&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  network_interface&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    network&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;hub&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;network_id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    subnetwork&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;hub&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;subnetwork_id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;spoke_vm&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  source&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;./modules/compute&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  for_each&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;spokes&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;spoke-${each.key}&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  network_interface&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    network&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;spoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;network_id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    subnetwork&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;spoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;subnetwork_id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Version fonctionnelle &lt;a class=&#34;link&#34; href=&#34;https://github.com/Bernedotcom2312/gcp-hub-and-spoke/tree/30c6b9a838f4472ba7d8e9f0cd6ca1456f42cc8a&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;ici&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;3-ajout-de-lifecycle&#34;&gt;&lt;a href=&#34;#3-ajout-de-lifecycle&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;3. Ajout de Lifecycle&#xA;&lt;/h3&gt;&lt;p&gt;Le VPC hub est une ressource critique de notre infrastructure puisque les deux spoke passe par lui.&#xA;Afin de faire échouer un plan si on tente un destroy sur cette ressource on peut s&amp;rsquo;appuyer sur le meta argument &lt;code&gt;lifecycle&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;google_compute_network&amp;#34; &amp;#34;hub&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name&lt;/span&gt;                    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hub-vpc&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  auto_create_subnetworks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;lifecycle&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    prevent_destroy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;4-bloc-de-validation&#34;&gt;&lt;a href=&#34;#4-bloc-de-validation&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;4. Bloc de validation&#xA;&lt;/h3&gt;&lt;p&gt;Dans la même idée on peut mettre en place une règle de validation sur le module vpc pour empêcher le chevauchement de cidr avec le hub.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;modules/vpc/variables.tf&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cidr&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Subnet CIDR range (e.g. 10.0.0.0/24)&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;validation&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    condition&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt; var.cidr !&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/24&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    error_message&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;The cidr range shouldn&amp;#39;t overlap with hub&amp;#39;s one.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un plan qui tente ce chevauchement aura ce message d&amp;rsquo;erreur :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;╷&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ Error: Invalid value &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; variable&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   on main.tf line 29, in module &lt;span class=&#34;s2&#34;&gt;&amp;#34;spoke&amp;#34;&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   29:   &lt;span class=&#34;nv&#34;&gt;cidr&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; each.value.cidr&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│     ├────────────────&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│     │ var.cidr is &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/24&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ The cidr range shouldn&lt;span class=&#34;s1&#34;&gt;&amp;#39;t overlap with hub&amp;#39;&lt;/span&gt;s one.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ This was checked by the validation rule at&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ modules/vpc/variables.tf:15,3-13.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;5-data-sources&#34;&gt;&lt;a href=&#34;#5-data-sources&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;5. Data sources&#xA;&lt;/h3&gt;&lt;p&gt;Autre ajout mineur mais qui permet de mettre en exergue l&amp;rsquo;instruction &lt;code&gt;data&lt;/code&gt;, l&amp;rsquo;image Debian est codée en dur (ex: &lt;code&gt;debian-cloud/debian-13&lt;/code&gt;). Si dans 6 mois Google dépréciée cette image, l&amp;rsquo;apply échoue. Avec &lt;code&gt;data &amp;quot;google_compute_image&amp;quot; { family = &amp;quot;debian-13&amp;quot;, project = &amp;quot;debian-cloud&amp;quot; }&lt;/code&gt;, Terraform récupère toujours la dernière image au moment de l&amp;rsquo;apply, sans maintenance manuelle.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;google_compute_image&amp;#34; &amp;#34;debian&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  family&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;debian-13&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  project&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;debian-cloud&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;google_compute_instance&amp;#34; &amp;#34;this&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.name}-vm&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  machine_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.machine_type}&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  zone&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;europe-west1-b&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;boot_disk&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;initialize_params&lt;/span&gt; {&lt;span class=&#34;c1&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;      #Utilisation de la data créée plus haut&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;google_compute_image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;debian&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;self_link&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;6-séparation-des-states&#34;&gt;&lt;a href=&#34;#6-s%c3%a9paration-des-states&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;6. Séparation des states&#xA;&lt;/h3&gt;&lt;p&gt;Enfin, un changement un peu plus costaud mais qui peut réellement être pertinent en entreprise : séparé la partie réseau dans un state dédié.&lt;/p&gt;&#xA;&lt;p&gt;A ce stade, modifier une VM oblige à revoir un plan qui inclut tout le réseau (VPC, firewall, routes), ce qui est risqué. En séparant en deux stacks (&lt;code&gt;network/&lt;/code&gt; et &lt;code&gt;compute/&lt;/code&gt;), l&amp;rsquo;équipe réseau pourrait appliquer ses changements indépendamment de l&amp;rsquo;équipe applicative. La partie &lt;code&gt;compute&lt;/code&gt; lit ensuite les infos du VPC via un bloc data qui pointe vers le state &lt;code&gt;network&lt;/code&gt; au lieu de dupliquer les valeurs en dur : si le réseau change, le compute suit automatiquement au prochain apply.&lt;/p&gt;&#xA;&lt;p&gt;Le découpage final peut être retrouvé &lt;a class=&#34;link&#34; href=&#34;https://github.com/Bernedotcom2312/gcp-hub-and-spoke/tree/45fba9b0c7469f5cc209d5600874e7f26d1c9340&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;ici&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Avant :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── main.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── providers.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── variables.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── modules/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── compute/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── firewall/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── peering/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── routing/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── vpc/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Après :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── modules/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── compute/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── firewall/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── peering/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── routing/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── vpc/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── network/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── main.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── outputs.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── providers.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── variables.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── compute/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── main.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── providers.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le dossier &lt;code&gt;modules/&lt;/code&gt; reste commun aux deux stacks. Ce qui était à la racine (&lt;code&gt;main.tf&lt;/code&gt;, &lt;code&gt;providers.tf&lt;/code&gt;, &lt;code&gt;variables.tf&lt;/code&gt;, donc un seul state) est éclaté en deux : &lt;code&gt;network/&lt;/code&gt; (VPC, subnets, firewall, peering, routing) et &lt;code&gt;compute/&lt;/code&gt; (VMs), chacun avec son propre backend et donc son propre state.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;compute/&lt;/code&gt; n&amp;rsquo;a plus de &lt;code&gt;variables.tf&lt;/code&gt; : il récupère les infos réseau via un bloc &lt;code&gt;data &amp;quot;terraform_remote_state&amp;quot;&lt;/code&gt; qui pointe vers le state de &lt;code&gt;network/&lt;/code&gt;, plutôt que de dupliquer des valeurs en dur.&lt;/p&gt;&#xA;&lt;h2 id=&#34;hcp-terraform&#34;&gt;&lt;a href=&#34;#hcp-terraform&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;HCP Terraform&#xA;&lt;/h2&gt;&lt;p&gt;Comme nous l&amp;rsquo;avons vu dans l&amp;rsquo;article précédent, HCP Terraform est la plateforme cloud d&amp;rsquo;Hashicorp.&#xA;J&amp;rsquo;ai voulu l&amp;rsquo;essayer pour découvrir plus en détail ses capacités.&lt;/p&gt;&#xA;&lt;h3 id=&#34;configuration&#34;&gt;&lt;a href=&#34;#configuration&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Configuration&#xA;&lt;/h3&gt;&lt;p&gt;Tout démarre via la création d&amp;rsquo;un compte Terraform/HCP, vous avez ensuite la possibilité de lier ce compte à un VCS. Pour ma part j&amp;rsquo;ai choisi de le faire pour bénéficier de l&amp;rsquo;intégration VCS avec Github.&lt;/p&gt;&#xA;&lt;p&gt;Enfin il faut créer une organisation, &lt;code&gt;bernedotcom&lt;/code&gt; pour ma part.&lt;/p&gt;&#xA;&lt;p&gt;Dernière étape : créer un &lt;code&gt;workspace&lt;/code&gt; pour cela vous avez deux possibilités :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Lancer terraform login depuis votre poste local + terraform init&lt;/li&gt;&#xA;&lt;li&gt;Le créer manuellement&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;migration-du-backend&#34;&gt;&lt;a href=&#34;#migration-du-backend&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Migration du backend&#xA;&lt;/h3&gt;&lt;p&gt;Il faut désormais indiquer à notre configuration que le backend est HCP désormais via l&amp;rsquo;instruction &lt;code&gt;cloud&lt;/code&gt;.&#xA;Suite à la séparation des states j&amp;rsquo;ai deux workspaces à gérer : gcp-hub-and-spoke-network et gcp-hub-and-spoke-compute.&lt;/p&gt;&#xA;&lt;p&gt;Voici un exemple de configuration dans &lt;code&gt;network/providers.tf&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;terraform&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;required_providers&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    google&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      source&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hashicorp/google&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;7.45.0&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  required_version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt; &amp;#34;&amp;gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;cloud&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    organization&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;bernedotcom&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;workspaces&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;gcp-hub-and-spoke-network&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un coup de terraform init pour valider tout ça et c&amp;rsquo;est terminé pour cette partie.&lt;/p&gt;&#xA;&lt;h3 id=&#34;service-account&#34;&gt;&lt;a href=&#34;#service-account&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Service account&#xA;&lt;/h3&gt;&lt;p&gt;Auparavant terraform était lancé depuis mon poste local et utilisait mon compte personnel GCP pour appliquer la configuration (ce n&amp;rsquo;est évidemment pas une bonne pratique).&#xA;Maintenant c&amp;rsquo;est HCP qui va lancer les plan &amp;amp; apply depuis une machine distante, il faut alors l&amp;rsquo;autoriser à faire ce type d&amp;rsquo;opérations sur mon projet GCP.&lt;/p&gt;&#xA;&lt;p&gt;Pour cela deux possibilités :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Un token d&amp;rsquo;authorization (peu secure)&lt;/li&gt;&#xA;&lt;li&gt;Workload identity (plus complexe à mettre en place mais beaucoup plus robuste).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;J&amp;rsquo;ai opté pour la workload identity ici :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 1. Activer les APIs nécessaires&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud services &lt;span class=&#34;nb&#34;&gt;enable&lt;/span&gt; iam.googleapis.com iamcredentials.googleapis.com sts.googleapis.com --project&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hubandspoke-demo&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 2. Créer le Workload Identity Pool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud iam workload-identity-pools create &lt;span class=&#34;s2&#34;&gt;&amp;#34;hcp-terraform-pool&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --project&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hubandspoke-demo&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --location&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;global&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --display-name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HCP Terraform&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 3. Créer le provider OIDC dans ce pool, restreint à org=bernedotcom / workspaces=gcp-hub-and-spoke-network,gcp-hub-and-spoke-compute&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud iam workload-identity-pools providers create-oidc &lt;span class=&#34;s2&#34;&gt;&amp;#34;hcp-terraform-provider&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --project&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hubandspoke-demo&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --location&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;global&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --workload-identity-pool&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hcp-terraform-pool&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --display-name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HCP Terraform Provider&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --attribute-mapping&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;google.subject=assertion.sub,attribute.terraform_organization_name=assertion.terraform_organization_name,attribute.terraform_workspace_name=assertion.terraform_workspace_name,attribute.terraform_run_phase=assertion.terraform_run_phase&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --attribute-condition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;assertion.terraform_organization_name==\&amp;#34;bernedotcom\&amp;#34; &amp;amp;&amp;amp; assertion.terraform_workspace_name in [\&amp;#34;gcp-hub-and-spoke-network\&amp;#34;, \&amp;#34;gcp-hub-and-spoke-compute\&amp;#34;]&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --issuer-uri&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;https://app.terraform.io&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 4. Créer le service account que Terraform utilisera&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud iam service-accounts create &lt;span class=&#34;s2&#34;&gt;&amp;#34;hcp-terraform-runner&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --project&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hubandspoke-demo&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --display-name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HCP Terraform runner&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 5. Lui donner les droits nécessaires sur le projet (couvre VPC, subnets, firewall, routeur/NAT, peering, VM)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud projects add-iam-policy-binding hubandspoke-demo &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --member&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;serviceAccount:hcp-terraform-runner@hubandspoke-demo.iam.gserviceaccount.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --role&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;roles/compute.networkAdmin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud projects add-iam-policy-binding hubandspoke-demo &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --member&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;serviceAccount:hcp-terraform-runner@hubandspoke-demo.iam.gserviceaccount.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --role&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;roles/compute.instanceAdmin.v1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# roles/compute.networkAdmin exclut explicitement les firewalls, il faut ce rôle en plus&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud projects add-iam-policy-binding hubandspoke-demo &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --member&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;serviceAccount:hcp-terraform-runner@hubandspoke-demo.iam.gserviceaccount.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --role&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;roles/compute.securityAdmin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 6. Autoriser le pool WIF à impersonate ce service account (uniquement depuis le workspace gcp-hub-and-spoke-network &amp;amp; compute)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud iam service-accounts add-iam-policy-binding &lt;span class=&#34;s2&#34;&gt;&amp;#34;hcp-terraform-runner@hubandspoke-demo.iam.gserviceaccount.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --project&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hubandspoke-demo&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --role&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;roles/iam.workloadIdentityUser&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --member&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;principalSet://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/hcp-terraform-pool/attribute.terraform_workspace_name/gcp-hub-and-spoke-network&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud iam service-accounts add-iam-policy-binding &lt;span class=&#34;s2&#34;&gt;&amp;#34;hcp-terraform-runner@hubandspoke-demo.iam.gserviceaccount.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --project&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hubandspoke-demo&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --role&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;roles/iam.workloadIdentityUser&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --member&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;principalSet://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/hcp-terraform-pool/attribute.terraform_workspace_name/gcp-hub-and-spoke-compute&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ensuite, dans les workspaces HCP Terraform (&lt;code&gt;bernedotcom/gcp-hub-and-spoke-network(compute)&lt;/code&gt; → Settings → Variables), ajouter en variables d&amp;rsquo;environnement :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;TFC_GCP_PROVIDER_AUTH&lt;/code&gt; = &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;TFC_GCP_RUN_SERVICE_ACCOUNT_EMAIL&lt;/code&gt; = &lt;code&gt;hcp-terraform-runner@hubandspoke-demo.iam.gserviceaccount.com&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;TFC_GCP_WORKLOAD_PROVIDER_NAME&lt;/code&gt; = &lt;code&gt;projects/123456789012/locations/global/workloadIdentityPools/hcp-terraform-pool/providers/hcp-terraform-provider&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;tour-dhorizon-de-lui&#34;&gt;&lt;a href=&#34;#tour-dhorizon-de-lui&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Tour d&amp;rsquo;horizon de l&amp;rsquo;UI&#xA;&lt;/h3&gt;&lt;p&gt;Grâce à l&amp;rsquo;intégration VCS le plan est ensuite automatiquement déclenché lors d&amp;rsquo;un nouveau commit sur la branche cible (main dans mon cas).&lt;/p&gt;&#xA;&lt;p&gt;Voici le résultat obtenu :&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;HCP Terraform Plan&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;336px&#34; data-flex-grow=&#34;140&#34; height=&#34;1220&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/plan.png&#34; srcset=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/plan_hu_fdb28111a3b49cce.png 800w, https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/plan_hu_f33d07f3ffd2d884.png 1600w, https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/plan.png 1710w&#34; width=&#34;1710&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Il est également possible d&amp;rsquo;obtenir la liste des derniers runs :&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;HCP Terraform last runs&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;487px&#34; data-flex-grow=&#34;202&#34; height=&#34;679&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/runs.png&#34; srcset=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/runs_hu_9303de6c45b94df2.png 800w, https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/runs.png 1378w&#34; width=&#34;1378&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Une fois un plan valide, il est alors possible de l&amp;rsquo;approuver manuellement pour application. Voici le résultat une fois l&amp;rsquo;apply lancé :&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;HCP Terraform run details&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;288px&#34; data-flex-grow=&#34;120&#34; height=&#34;1103&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/run_details.png&#34; srcset=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/run_details_hu_16c5f55dd666daf8.png 800w, https://valerian-pyckaert.dev/posts/terraform-associate-hub-spoke-gcp/run_details.png 1324w&#34; width=&#34;1324&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;vérification&#34;&gt;&lt;a href=&#34;#v%c3%a9rification&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Vérification&#xA;&lt;/h2&gt;&lt;p&gt;Une fois la totalité des ressources créées il s&amp;rsquo;agit de vérifier le bon fonctionnement de l&amp;rsquo;architecture; pour cela rien de compliqué :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud compute ssh spoke-dev-vm --zone&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;europe-west1-b --tunnel-through-iap&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# from spoke-dev-vm&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping 10.0.0.2   &lt;span class=&#34;c1&#34;&gt;# hub — should succeed&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping 10.2.0.2   &lt;span class=&#34;c1&#34;&gt;# spoke-prod — should time out&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;conclusion&#34;&gt;&lt;a href=&#34;#conclusion&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Conclusion&#xA;&lt;/h2&gt;&lt;p&gt;Cette mise en place d&amp;rsquo;une architecture hub &amp;amp; spoke aura permis de mettre en application concrètement les notions vues tout au long de ma préparation à la certification Terraform Associate. Je suis également satisfait de cet essai d&amp;rsquo;HCP Terraform : la plateforme est agréable à utiliser et tout s&amp;rsquo;est déroulé sans difficulté, de la configuration du workspace jusqu&amp;rsquo;à la workload identity. On obtient une solution GitOps friendly clé en main, sans avoir à gérer soi-même un backend distant ni un pipeline CI/CD pour Terraform.&lt;/p&gt;&#xA;&lt;p&gt;La version finale de l&amp;rsquo;implémentation est disponible &lt;a class=&#34;link&#34; href=&#34;https://github.com/Bernedotcom2312/gcp-hub-and-spoke&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;ici&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #7 — HCP Terraform</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-hcp-terraform/</link>
            <pubDate>Tue, 18 Aug 2026 17:30:00 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-hcp-terraform/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-hcp-terraform/module7.png&#34; alt=&#34;Featured image of post Terraform Associate #7 — HCP Terraform&#34; /&gt;&lt;p&gt;Suite de ma série sur la certification &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt;, après &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-state-management/&#34; &gt;le module sur le state&lt;/a&gt;. Dernier objectif de l&amp;rsquo;exam guide, &amp;ldquo;Understand HCP Terraform capabilities&amp;rdquo; : cet article couvre les workspaces, l&amp;rsquo;intégration VCS, le registre privé, Sentinel/OPA et l&amp;rsquo;exécution en automation.&lt;/p&gt;&#xA;&lt;h2 id=&#34;quest-ce-que-hcp-terraform&#34;&gt;&lt;a href=&#34;#quest-ce-que-hcp-terraform&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Qu&amp;rsquo;est-ce que HCP Terraform&#xA;&lt;/h2&gt;&lt;p&gt;HCP Terraform (anciennement Terraform Cloud) est le service managé de HashiCorp : state distant, locking, runs &lt;code&gt;plan&lt;/code&gt;/&lt;code&gt;apply&lt;/code&gt; centralisés, et couche de gouvernance en plus du CLI open source.&lt;/p&gt;&#xA;&lt;h2 id=&#34;workspaces--cli-vs-hcp-terraform&#34;&gt;&lt;a href=&#34;#workspaces--cli-vs-hcp-terraform&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Workspaces : CLI vs HCP Terraform&#xA;&lt;/h2&gt;&lt;p&gt;Le mot &amp;ldquo;workspace&amp;rdquo; désigne deux choses différentes selon le contexte :&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Workspace CLI (OSS)&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Workspace HCP Terraform&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Portée&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Plusieurs états pour une même configuration locale (&lt;code&gt;terraform workspace new&lt;/code&gt;)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Unité complète : configuration + variables + state + historique des runs&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;State&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Un fichier par workspace, même backend&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;State propre à chaque workspace&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Isolation&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Faible, même répertoire de code&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Forte, généralement un repo/dossier ↔ un workspace&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Un workspace HCP Terraform correspond en général à un environnement (dev/staging/prod) ou un composant d&amp;rsquo;infrastructure, chacun avec ses propres variables et son propre historique.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Les workspaces peuvent partager des informations entre eux via des outputs racine.&lt;/li&gt;&#xA;&lt;li&gt;Un workspace utilisant l&amp;rsquo;exécution distante peut accéder aux outputs d&amp;rsquo;un autre workspace via une source de données &lt;code&gt;terraform_remote_state&lt;/code&gt;, sous réserve des contrôles d&amp;rsquo;accès par workspace.&lt;/li&gt;&#xA;&lt;li&gt;Des run triggers workspace-à-workspace permettent de faire réagir automatiquement un workspace en aval quand ses dépendances changent.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;intégration-vcs&#34;&gt;&lt;a href=&#34;#int%c3%a9gration-vcs&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Intégration VCS&#xA;&lt;/h2&gt;&lt;p&gt;Un workspace peut être connecté à un dépôt Git (GitHub, GitLab, Bitbucket&amp;hellip;). Chaque push ou pull request déclenche automatiquement un run.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Génère un &lt;code&gt;plan&lt;/code&gt; en preview sur les pull requests, avant merge.&lt;/li&gt;&#xA;&lt;li&gt;Déclenche un &lt;code&gt;apply&lt;/code&gt; sur push vers la branche configurée (selon le mode d&amp;rsquo;apply du workspace).&lt;/li&gt;&#xA;&lt;li&gt;Évite d&amp;rsquo;exécuter Terraform depuis un poste local : le run s&amp;rsquo;exécute sur l&amp;rsquo;infrastructure HCP Terraform.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;registre-privé&#34;&gt;&lt;a href=&#34;#registre-priv%c3%a9&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Registre privé&#xA;&lt;/h2&gt;&lt;p&gt;En plus du Terraform Registry public, HCP Terraform propose un registre privé pour publier des modules et des providers internes, avec la même syntaxe &lt;code&gt;source = &amp;quot;app.terraform.io/&amp;lt;org&amp;gt;/&amp;lt;nom&amp;gt;/&amp;lt;provider&amp;gt;&amp;quot;&lt;/code&gt; que le registre public.&lt;/p&gt;&#xA;&lt;h2 id=&#34;estimation-des-coûts&#34;&gt;&lt;a href=&#34;#estimation-des-co%c3%bbts&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Estimation des coûts&#xA;&lt;/h2&gt;&lt;p&gt;HCP Terraform peut estimer le coût mensuel des ressources créées, modifiées ou détruites par un &lt;code&gt;plan&lt;/code&gt;, pour les providers supportés (AWS, Azure, GCP).&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;L&amp;rsquo;estimation apparaît directement dans le run, avant l&amp;rsquo;&lt;code&gt;apply&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Elle peut être utilisée dans une policy Sentinel (ex. bloquer un plan si le delta de coût dépasse un seuil).&lt;/li&gt;&#xA;&lt;li&gt;Elle reste une estimation basée sur le pricing public du provider, pas une facture réelle (remises, réservations&amp;hellip; non prises en compte).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;sentinel-et-opa&#34;&gt;&lt;a href=&#34;#sentinel-et-opa&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Sentinel et OPA&#xA;&lt;/h2&gt;&lt;p&gt;Sentinel (propriétaire HashiCorp) et Open Policy Agent (OPA) permettent d&amp;rsquo;appliquer du &lt;strong&gt;policy as code&lt;/strong&gt; : des règles évaluées automatiquement entre le &lt;code&gt;plan&lt;/code&gt; et l&amp;rsquo;&lt;code&gt;apply&lt;/code&gt;, pour bloquer un changement qui ne respecte pas une politique organisationnelle.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# exemple de règle Sentinel&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main = rule {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  all tfplan.resources.aws_instance as _, instances {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    all instances as _, r {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      r.applied.instance_type in [&amp;#34;t3.micro&amp;#34;, &amp;#34;t3.small&amp;#34;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Advisory&lt;/strong&gt; : avertit sans bloquer.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Soft mandatory&lt;/strong&gt; : bloque, mais un utilisateur autorisé peut passer outre.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Hard mandatory&lt;/strong&gt; : bloque sans possibilité de contournement.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Cas d&amp;rsquo;usage typiques : imposer des tags obligatoires, restreindre les types d&amp;rsquo;instance autorisés, interdire l&amp;rsquo;ouverture de ports sensibles.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-tasks&#34;&gt;&lt;a href=&#34;#run-tasks&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Run tasks&#xA;&lt;/h2&gt;&lt;p&gt;Les &lt;strong&gt;run tasks&lt;/strong&gt; intègrent un service tiers (scan de sécurité, coût, conformité&amp;hellip;) dans le cycle de vie d&amp;rsquo;un run, à un stade précis (&lt;code&gt;post-plan&lt;/code&gt;, &lt;code&gt;pre-apply&lt;/code&gt;, &lt;code&gt;post-apply&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;HCP Terraform envoie les détails du run à l&amp;rsquo;endpoint du service tiers via une API webhook.&lt;/li&gt;&#xA;&lt;li&gt;Le service répond avec un statut &lt;code&gt;passed&lt;/code&gt; ou &lt;code&gt;failed&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Comme Sentinel/OPA, la sévérité peut être &lt;strong&gt;advisory&lt;/strong&gt; (informatif) ou &lt;strong&gt;mandatory&lt;/strong&gt; (bloque l&amp;rsquo;apply si le check échoue).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Contrairement à Sentinel/OPA qui évalue localement le plan avec des règles écrites en Sentinel ou Rego, un run task délègue la vérification à un outil externe (ex. Snyk, Bridgecrew, Infracost).&lt;/p&gt;&#xA;&lt;h2 id=&#34;rbac&#34;&gt;&lt;a href=&#34;#rbac&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;RBAC&#xA;&lt;/h2&gt;&lt;p&gt;HCP Terraform gère les permissions à deux niveaux :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Niveau organisation&lt;/strong&gt; : rôles Owner, ou permissions personnalisées (gestion des membres, des teams, des paramètres).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Niveau workspace&lt;/strong&gt; : accès par team, avec des permissions fixes (Read, Plan, Write, Admin) ou personnalisées (ex. autoriser l&amp;rsquo;apply sans donner accès aux variables sensibles).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Les teams regroupent des utilisateurs et se voient assigner des permissions par workspace, ce qui permet par exemple de restreindre l&amp;rsquo;apply en prod à une team dédiée.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-triggers-et-notifications&#34;&gt;&lt;a href=&#34;#run-triggers-et-notifications&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Run triggers et notifications&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;Les &lt;strong&gt;run triggers&lt;/strong&gt; permettent de chaîner des workspaces : un apply réussi sur un workspace peut déclencher automatiquement un run sur un autre (ex. réseau → applicatif).&lt;/li&gt;&#xA;&lt;li&gt;Les &lt;strong&gt;notifications&lt;/strong&gt; (Slack, email, webhook générique) informent des événements d&amp;rsquo;un workspace (run créé, en attente, terminé, erreur).&lt;/li&gt;&#xA;&lt;li&gt;Les run triggers sont destinés aux workspaces qui dépendent d&amp;rsquo;informations ou d&amp;rsquo;infrastructure produites par d&amp;rsquo;autres workspaces.&lt;/li&gt;&#xA;&lt;li&gt;Un run déclenché par un run trigger n&amp;rsquo;est pas auto-appliqué, sauf si l&amp;rsquo;option &amp;ldquo;Auto-apply run triggers&amp;rdquo; est activée.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;workspaces-vs-stacks&#34;&gt;&lt;a href=&#34;#workspaces-vs-stacks&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Workspaces vs Stacks&#xA;&lt;/h2&gt;&lt;p&gt;HCP Terraform Stacks est une fonctionnalité pour orchestrer plusieurs composants d&amp;rsquo;infrastructure liés comme une seule unité :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Workspace&lt;/strong&gt; : une configuration, un state, un cycle de vie indépendant. Pour chaîner plusieurs workspaces (ex. réseau → applicatif), il faut des run triggers ou de l&amp;rsquo;orchestration externe.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Stack&lt;/strong&gt; : regroupe plusieurs composants (chacun avec son propre state) déployés ensemble sur plusieurs environnements ou régions, avec un ordonnancement natif des dépendances entre composants et une configuration écrite en langage Terraform Stacks (basé sur HCL, fichiers &lt;code&gt;.tfcomponent.hcl&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;En résumé, un Stack remplace le pattern &amp;ldquo;plusieurs workspaces + run triggers&amp;rdquo; par une orchestration native quand les composants sont fortement couplés.&lt;/p&gt;&#xA;&lt;pre class=&#34;mermaid&#34; style=&#34;visibility:hidden&#34;&gt;graph TD&#xA;    Org[Organisation] --&gt; Proj[Projet]&#xA;    Proj --&gt; WS1[Workspace: réseau]&#xA;    Proj --&gt; WS2[Workspace: applicatif]&#xA;    Proj --&gt; Stack[Stack]&#xA;    Stack --&gt; C1[Composant: state 1]&#xA;    Stack --&gt; C2[Composant: state 2]&lt;/pre&gt;&lt;h2 id=&#34;health-checks&#34;&gt;&lt;a href=&#34;#health-checks&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Health checks&#xA;&lt;/h2&gt;&lt;p&gt;HCP Terraform peut vérifier périodiquement l&amp;rsquo;état d&amp;rsquo;un workspace en dehors des runs déclenchés manuellement :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Drift detection&lt;/strong&gt; : lance un &lt;code&gt;plan&lt;/code&gt; régulier pour détecter si l&amp;rsquo;infrastructure réelle a divergé du state (changement fait hors Terraform).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Continuous validation&lt;/strong&gt; : réévalue en continu les blocs &lt;code&gt;check&lt;/code&gt; de la configuration (ex. certificat encore valide, endpoint toujours joignable) même sans nouveau run.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Ces contrôles remontent des alertes sans forcément déclencher d&amp;rsquo;apply, ce qui aide à repérer une dérive avant qu&amp;rsquo;elle ne cause un incident.&lt;/p&gt;&#xA;&lt;h2 id=&#34;exécution-en-automation&#34;&gt;&lt;a href=&#34;#ex%c3%a9cution-en-automation&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Exécution en automation&#xA;&lt;/h2&gt;&lt;p&gt;HCP Terraform peut lancer des runs via trois mécanismes :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;VCS-driven&lt;/strong&gt; : déclenché par un push/PR sur le dépôt connecté (voir ci-dessus).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;API-driven&lt;/strong&gt; : déclenché par un appel à l&amp;rsquo;API HCP Terraform, utile pour l&amp;rsquo;intégrer à un pipeline CI/CD externe.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;CLI-driven&lt;/strong&gt; : &lt;code&gt;terraform plan&lt;/code&gt;/&lt;code&gt;apply&lt;/code&gt; lancés localement, mais exécutés à distance sur HCP Terraform grâce au bloc &lt;code&gt;cloud&lt;/code&gt; (voir &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-state-management/#hcp-terraform&#34; &gt;l&amp;rsquo;article sur le state&lt;/a&gt;).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Dans les trois cas, l&amp;rsquo;exécution du run (et l&amp;rsquo;accès aux credentials associés) a lieu sur l&amp;rsquo;infrastructure HCP Terraform, pas sur le poste ou l&amp;rsquo;agent qui déclenche l&amp;rsquo;opération.&lt;/p&gt;&#xA;&lt;h2 id=&#34;migrer-son-state-vers-hcp-terraform&#34;&gt;&lt;a href=&#34;#migrer-son-state-vers-hcp-terraform&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Migrer son state vers HCP Terraform&#xA;&lt;/h2&gt;&lt;p&gt;Pour basculer un state existant (local ou backend distant type S3) vers HCP Terraform :&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Ajouter un bloc &lt;code&gt;cloud&lt;/code&gt; dans la configuration, avec l&amp;rsquo;organisation et le nom du workspace cible :&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;terraform&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;cloud&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    organization&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mon-org&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;workspaces&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mon-workspace&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#xA;&lt;li&gt;Lancer &lt;code&gt;terraform login&lt;/code&gt; pour s&amp;rsquo;authentifier auprès de HCP Terraform.&lt;/li&gt;&#xA;&lt;li&gt;Lancer &lt;code&gt;terraform init&lt;/code&gt; : Terraform détecte l&amp;rsquo;ancien backend et propose de migrer le state existant vers le workspace HCP Terraform.&lt;/li&gt;&#xA;&lt;li&gt;Confirmer la migration : le state est copié, le workspace HCP Terraform en devient la nouvelle source de vérité.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Une fois migré, le mode d&amp;rsquo;exécution du workspace (remote par défaut, ou local) détermine si les &lt;code&gt;plan&lt;/code&gt;/&lt;code&gt;apply&lt;/code&gt; s&amp;rsquo;exécutent sur l&amp;rsquo;infrastructure HCP Terraform ou toujours en local avec state distant.&lt;/p&gt;&#xA;&lt;h2 id=&#34;ce-que-je-retiens&#34;&gt;&lt;a href=&#34;#ce-que-je-retiens&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce que je retiens&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Workspace CLI ≠ workspace HCP Terraform&lt;/strong&gt; : le premier isole un state, le second isole un environnement complet (config, variables, historique).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Sentinel/OPA s&amp;rsquo;évaluent entre &lt;code&gt;plan&lt;/code&gt; et &lt;code&gt;apply&lt;/code&gt;&lt;/strong&gt; : c&amp;rsquo;est le point de contrôle pour bloquer un changement non conforme avant qu&amp;rsquo;il ne soit appliqué.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Trois façons de déclencher un run&lt;/strong&gt; : VCS, API ou CLI, mais l&amp;rsquo;exécution reste toujours centralisée côté HCP Terraform.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Fin de cette série sur le &amp;ldquo;learning path&amp;rdquo; Terraform Associate.&#xA;La suite consistera à développer un projet pour mettre en application toutes les connaissances acquises avec le learning path.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #6 — Le state</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-state-management/</link>
            <pubDate>Tue, 18 Aug 2026 16:05:00 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-state-management/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-state-management/module6.png&#34; alt=&#34;Featured image of post Terraform Associate #6 — Le state&#34; /&gt;&lt;p&gt;Suite de ma série sur la certification &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt;, après &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-modules/&#34; &gt;les modules&lt;/a&gt;. Sixième objectif de l&amp;rsquo;exam guide, &amp;ldquo;Implement and maintain state&amp;rdquo; : cet article couvre le backend local, le locking, le remote state, l&amp;rsquo;authentification et la gestion des secrets dans le state.&lt;/p&gt;&#xA;&lt;h2 id=&#34;quest-ce-que-le-state&#34;&gt;&lt;a href=&#34;#quest-ce-que-le-state&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Qu&amp;rsquo;est-ce que le state&#xA;&lt;/h2&gt;&lt;p&gt;Le state est un fichier (&lt;code&gt;terraform.tfstate&lt;/code&gt;, au format JSON) dans lequel Terraform stocke le mapping entre les ressources déclarées dans la configuration et les objets réels de l&amp;rsquo;infrastructure. C&amp;rsquo;est ce fichier qui permet à Terraform de savoir quoi créer, modifier ou détruire à chaque &lt;code&gt;plan&lt;/code&gt;/&lt;code&gt;apply&lt;/code&gt;, sans avoir à interroger l&amp;rsquo;ensemble du provider à chaque fois.&lt;/p&gt;&#xA;&lt;h2 id=&#34;backend-local&#34;&gt;&lt;a href=&#34;#backend-local&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Backend local&#xA;&lt;/h2&gt;&lt;p&gt;Par défaut, Terraform utilise le backend &lt;code&gt;local&lt;/code&gt; : le state est stocké dans un fichier &lt;code&gt;terraform.tfstate&lt;/code&gt; à la racine du répertoire de travail.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Simple à utiliser, aucune configuration requise.&lt;/li&gt;&#xA;&lt;li&gt;Ne convient pas au travail en équipe : pas de lock partagé, pas de state partagé entre collaborateurs, secret stocké en clair sur le poste local.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;state-locking&#34;&gt;&lt;a href=&#34;#state-locking&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;State locking&#xA;&lt;/h2&gt;&lt;p&gt;Avant toute opération qui écrit dans le state (&lt;code&gt;apply&lt;/code&gt;, parfois &lt;code&gt;plan&lt;/code&gt;), Terraform tente de le verrouiller pour empêcher deux opérations concurrentes de le corrompre.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Le locking est supporté par la plupart des backends distants (S3, Azure Blob Storage, HCP Terraform&amp;hellip;)&lt;/li&gt;&#xA;&lt;li&gt;Si le lock ne peut pas être acquis, Terraform bloque l&amp;rsquo;opération et indique qui détient le lock.&lt;/li&gt;&#xA;&lt;li&gt;L&amp;rsquo;option &lt;code&gt;-lock=false&lt;/code&gt; permet de désactiver ce comportement, à éviter en usage normal.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;backend-distant&#34;&gt;&lt;a href=&#34;#backend-distant&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Backend distant&#xA;&lt;/h2&gt;&lt;p&gt;Un backend distant stocke le state en dehors du poste local (bucket S3, Azure Blob Storage, GCS, HCP Terraform&amp;hellip;). Il se déclare dans un bloc &lt;code&gt;backend&lt;/code&gt;, imbriqué dans le bloc &lt;code&gt;terraform&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;terraform&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;backend&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;s3&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    bucket&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mon-bucket-tfstate&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    key&lt;/span&gt;            &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;prod/network/terraform.tfstate&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    region&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;eu-west-1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    dynamodb_table&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;terraform-locks&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    encrypt&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Avantages par rapport au backend local :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;State partagé entre plusieurs collaborateurs ou pipelines CI/CD.&lt;/li&gt;&#xA;&lt;li&gt;Locking natif.&lt;/li&gt;&#xA;&lt;li&gt;Chiffrement.&lt;/li&gt;&#xA;&lt;li&gt;Historique/versionning du state selon le backend.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Changer de backend nécessite de relancer &lt;code&gt;terraform init&lt;/code&gt;, qui propose alors de migrer le state existant vers le nouveau backend.&lt;/p&gt;&#xA;&lt;h2 id=&#34;hcp-terraform&#34;&gt;&lt;a href=&#34;#hcp-terraform&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;HCP Terraform&#xA;&lt;/h2&gt;&lt;p&gt;HCP Terraform (anciennement Terraform Cloud) peut aussi servir de backend, via un bloc &lt;code&gt;cloud&lt;/code&gt; plutôt que &lt;code&gt;backend&lt;/code&gt; :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;terraform&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;cloud&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    organization&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mon-org&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;workspaces&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;prod-network&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En plus du stockage du state, HCP Terraform ajoute le locking, un historique des runs, et l&amp;rsquo;exécution du plan/apply à distance.&lt;/p&gt;&#xA;&lt;h2 id=&#34;authentification-aux-backends&#34;&gt;&lt;a href=&#34;#authentification-aux-backends&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Authentification aux backends&#xA;&lt;/h2&gt;&lt;p&gt;Chaque backend a son propre mécanisme d&amp;rsquo;authentification, indépendant de celui des providers :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;S3&lt;/strong&gt; : credentials AWS (variables d&amp;rsquo;environnement, profil CLI, rôle IAM).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Azure Blob Storage&lt;/strong&gt; : Azure CLI, service principal, managed identity.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;HCP Terraform&lt;/strong&gt; : token d&amp;rsquo;API, généralement stocké dans &lt;code&gt;~/.terraform.d/credentials.tfrc.json&lt;/code&gt; via &lt;code&gt;terraform login&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Ces credentials ne doivent jamais être codés en dur dans la configuration.&lt;/p&gt;&#xA;&lt;h2 id=&#34;effet-de-terraform-refresh&#34;&gt;&lt;a href=&#34;#effet-de-terraform-refresh&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Effet de terraform refresh&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;terraform refresh&lt;/code&gt; (ou l&amp;rsquo;étape de refresh implicite lors d&amp;rsquo;un &lt;code&gt;plan&lt;/code&gt;/&lt;code&gt;apply&lt;/code&gt;) interroge les providers pour comparer l&amp;rsquo;état réel de l&amp;rsquo;infrastructure au state enregistré, et met à jour le state en conséquence.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Ne modifie &lt;strong&gt;jamais&lt;/strong&gt; l&amp;rsquo;infrastructure réelle, uniquement le fichier de state.&lt;/li&gt;&#xA;&lt;li&gt;Permet de détecter un drift (modification manuelle en dehors de Terraform).&lt;/li&gt;&#xA;&lt;li&gt;Peut être désactivé avec &lt;code&gt;-refresh=false&lt;/code&gt; pour accélérer un plan quand on est sûr qu&amp;rsquo;il n&amp;rsquo;y a pas eu de changement externe.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;secrets-dans-le-state&#34;&gt;&lt;a href=&#34;#secrets-dans-le-state&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Secrets dans le state&#xA;&lt;/h2&gt;&lt;p&gt;Le state contient les valeurs de &lt;strong&gt;toutes&lt;/strong&gt; les ressources qu&amp;rsquo;il suit, y compris les attributs sensibles (mots de passe générés, clés, tokens), même si la variable ou l&amp;rsquo;output correspondant est marqué &lt;code&gt;sensitive&lt;/code&gt;. Comme évoqué dans &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-configuration/#g%c3%a9rer-les-donn%c3%a9es-sensibles&#34; &gt;l&amp;rsquo;article sur la configuration&lt;/a&gt;, &lt;code&gt;sensitive&lt;/code&gt; masque seulement l&amp;rsquo;affichage dans les logs et l&amp;rsquo;UI, il ne retire rien du state.&lt;/p&gt;&#xA;&lt;p&gt;Bonnes pratiques :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Toujours utiliser un backend distant chiffré &lt;strong&gt;at rest&lt;/strong&gt; plutôt que le backend local.&lt;/li&gt;&#xA;&lt;li&gt;Restreindre l&amp;rsquo;accès au state via des contrôles d&amp;rsquo;accès (IAM, permissions du backend).&lt;/li&gt;&#xA;&lt;li&gt;Activer les logs d&amp;rsquo;audit du backend pour tracer les accès au state.&lt;/li&gt;&#xA;&lt;li&gt;Préférer &lt;code&gt;ephemeral&lt;/code&gt;/write-only quand c&amp;rsquo;est possible, pour éviter que la valeur n&amp;rsquo;atterrisse dans le state.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;commandes-terraform-state&#34;&gt;&lt;a href=&#34;#commandes-terraform-state&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Commandes terraform state&#xA;&lt;/h2&gt;&lt;p&gt;Terraform fournit un sous-ensemble de commandes dédiées à l&amp;rsquo;inspection et la manipulation du state, sans passer par un &lt;code&gt;apply&lt;/code&gt; :&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform state list                    &lt;span class=&#34;c1&#34;&gt;# liste les ressources trackées&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform state show aws_instance.web   &lt;span class=&#34;c1&#34;&gt;# détail d&amp;#39;une ressource dans le state&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform state mv aws_instance.web aws_instance.app   &lt;span class=&#34;c1&#34;&gt;# renomme/déplace une ressource dans le state&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform state rm aws_instance.web     &lt;span class=&#34;c1&#34;&gt;# retire une ressource du state (sans la détruire)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform state pull                    &lt;span class=&#34;c1&#34;&gt;# affiche le state distant au format JSON&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform state push                    &lt;span class=&#34;c1&#34;&gt;# écrase le state distant (usage avancé, à risque)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;terraform state list&lt;/code&gt; est généralement la première commande à lancer pour retrouver l&amp;rsquo;adresse exacte d&amp;rsquo;une ressource avant d&amp;rsquo;utiliser &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt; ou &lt;code&gt;rm&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;importer-une-ressource-existante&#34;&gt;&lt;a href=&#34;#importer-une-ressource-existante&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Importer une ressource existante&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;terraform import&lt;/code&gt; rattache une ressource déjà existante (créée manuellement ou par un autre outil) à un bloc &lt;code&gt;resource&lt;/code&gt; du state, sans la recréer.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform import aws_instance.web i-0abcd1234&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Le bloc &lt;code&gt;resource &amp;quot;aws_instance&amp;quot; &amp;quot;web&amp;quot; { ... }&lt;/code&gt; doit déjà exister dans la configuration : la commande ne fait qu&amp;rsquo;ajouter l&amp;rsquo;entrée au state, elle ne génère aucun HCL.&lt;/li&gt;&#xA;&lt;li&gt;Il faut ensuite compléter le bloc à la main pour que la configuration corresponde à la ressource réelle, sinon le prochain &lt;code&gt;plan&lt;/code&gt; proposera des changements pour aligner l&amp;rsquo;un sur l&amp;rsquo;autre.&lt;/li&gt;&#xA;&lt;li&gt;Fonctionne ressource par ressource : pas d&amp;rsquo;import groupé avec la commande CLI.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;logs&#34;&gt;&lt;a href=&#34;#logs&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Logs&#xA;&lt;/h2&gt;&lt;p&gt;Terraform expose des logs de debug via la variable d&amp;rsquo;environnement &lt;code&gt;TF_LOG&lt;/code&gt;, utile pour diagnostiquer un comportement inattendu (au niveau du core ou d&amp;rsquo;un provider).&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;TF_LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;DEBUG&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform plan&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Niveaux disponibles, du plus verbeux au moins verbeux : &lt;code&gt;TRACE&lt;/code&gt;, &lt;code&gt;DEBUG&lt;/code&gt;, &lt;code&gt;INFO&lt;/code&gt;, &lt;code&gt;WARN&lt;/code&gt;, &lt;code&gt;ERROR&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;TF_LOG_CORE&lt;/code&gt; et &lt;code&gt;TF_LOG_PROVIDER&lt;/code&gt; permettent de cibler respectivement le cœur de Terraform ou les providers, indépendamment l&amp;rsquo;un de l&amp;rsquo;autre.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;TF_LOG_PATH&lt;/code&gt; redirige les logs vers un fichier plutôt que stdout/stderr :&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;TF_LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;TRACE&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;TF_LOG_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./terraform.log&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Penser à &lt;code&gt;unset TF_LOG&lt;/code&gt; (et &lt;code&gt;TF_LOG_PATH&lt;/code&gt;) une fois le diagnostic terminé, sinon chaque commande reste verbeuse.&lt;/li&gt;&#xA;&lt;li&gt;Ces logs tracent l&amp;rsquo;exécution du CLI (appels aux providers, résolution de la configuration&amp;hellip;), sans lien avec le contenu du state.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;ce-que-je-retiens&#34;&gt;&lt;a href=&#34;#ce-que-je-retiens&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce que je retiens&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Le backend local ne convient pas au travail en équipe&lt;/strong&gt; : pas de locking partagé, secrets en clair sur le poste.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;sensitive&lt;/code&gt; ≠ absent du state&lt;/strong&gt; : seul &lt;code&gt;ephemeral&lt;/code&gt; garantit qu&amp;rsquo;une valeur n&amp;rsquo;y est jamais écrite.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;terraform refresh&lt;/code&gt; ne touche jamais l&amp;rsquo;infrastructure réelle&lt;/strong&gt;, seulement le fichier de state, pour détecter un drift.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;terraform import&lt;/code&gt; rattache une ressource existante au state sans la recréer&lt;/strong&gt;, mais ne génère pas la configuration correspondante : à compléter à la main.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;TF_LOG&lt;/code&gt; cible le core ou les providers séparément&lt;/strong&gt; (&lt;code&gt;TF_LOG_CORE&lt;/code&gt;/&lt;code&gt;TF_LOG_PROVIDER&lt;/code&gt;), et n&amp;rsquo;a aucun effet sur le contenu du state.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Prochaine (et dernière) étape de la série : HCP Terraform.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #5 — Les modules</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-modules/</link>
            <pubDate>Mon, 17 Aug 2026 16:44:02 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-modules/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-modules/module5.png&#34; alt=&#34;Featured image of post Terraform Associate #5 — Les modules&#34; /&gt;&lt;p&gt;Nous en sommes à un peu plus de la moitié du learning path pour l&amp;rsquo;obtention de la certification &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt;, après &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-configuration/&#34; &gt;le module sur la configuration&lt;/a&gt;. Cinquième objectif de l&amp;rsquo;exam guide, &amp;ldquo;Interact with Terraform modules&amp;rdquo; : cet article couvre les sources de module, les inputs/outputs, la portée des variables et le versionning.&lt;/p&gt;&#xA;&lt;h2 id=&#34;quest-ce-quun-module&#34;&gt;&lt;a href=&#34;#quest-ce-quun-module&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Qu&amp;rsquo;est-ce qu&amp;rsquo;un module&#xA;&lt;/h2&gt;&lt;p&gt;Un module est un ensemble de fichiers &lt;code&gt;.tf&lt;/code&gt; regroupés dans un même répertoire. Chaque configuration Terraform a au moins un module : le &lt;strong&gt;module racine&lt;/strong&gt;, celui dans lequel on lance &lt;code&gt;terraform apply&lt;/code&gt;. Les modules qu&amp;rsquo;il appelle sont des &lt;strong&gt;modules enfants&lt;/strong&gt;, et peuvent eux-mêmes en appeler d&amp;rsquo;autres.&lt;/p&gt;&#xA;&lt;p&gt;Regrouper des ressources dans un module permet de les réutiliser, de les partager entre équipes et de simplifier la configuration racine.&lt;/p&gt;&#xA;&lt;h2 id=&#34;utilisation&#34;&gt;&lt;a href=&#34;#utilisation&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Utilisation&#xA;&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;consul&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  source&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hashicorp/consul/aws&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0.1.0&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  servers&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;source&lt;/code&gt; est le seul argument obligatoire : il indique où trouver le code du module.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;terraform init&lt;/code&gt; télécharge et met en cache tout module référencé par la configuration.&lt;/li&gt;&#xA;&lt;li&gt;Les autres arguments du bloc (&lt;code&gt;servers&lt;/code&gt; ici) correspondent aux variables d&amp;rsquo;input déclarées par le module.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;sources-de-module&#34;&gt;&lt;a href=&#34;#sources-de-module&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Sources de module&#xA;&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;argument &lt;code&gt;source&lt;/code&gt; détermine où et comment Terraform va chercher le module :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Chemin local&lt;/strong&gt; (&lt;code&gt;./modules/consul&lt;/code&gt;) : pas de téléchargement, le module suit le cycle de vie du code parent. Ne supporte pas le versionning.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Terraform Registry&lt;/strong&gt; (&lt;code&gt;hashicorp/consul/aws&lt;/code&gt;, format &lt;code&gt;&amp;lt;namespace&amp;gt;/&amp;lt;nom&amp;gt;/&amp;lt;provider&amp;gt;&lt;/code&gt;) : source la plus courante pour les modules publics ou privés.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;GitHub / Git / HTTP&lt;/strong&gt; (&lt;code&gt;git::https://example.com/vpc.git&lt;/code&gt;) : utile pour des modules non publiés sur un registre.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Buckets S3 / GCS&lt;/strong&gt; : pour des modules stockés en interne sans registre dédié.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Seules les sources de registre (public ou privé) supportent l&amp;rsquo;argument &lt;code&gt;version&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;inputs-et-outputs&#34;&gt;&lt;a href=&#34;#inputs-et-outputs&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Inputs et outputs&#xA;&lt;/h2&gt;&lt;p&gt;Un module communique avec l&amp;rsquo;extérieur via des variables d&amp;rsquo;input et des outputs, comme évoqué dans l&amp;rsquo;article précédent sur les &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-configuration/#variables--outputs&#34; &gt;variables &amp;amp; outputs&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# modules/vpc/variables.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cidr_block&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&lt;span class=&#34;c1&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# modules/vpc/outputs.tf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vpc_id&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;aws_vpc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# racine&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;network&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  source&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;./modules/vpc&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  cidr_block&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;aws_subnet&amp;#34; &amp;#34;web&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  vpc_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;network&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;vpc_id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Les inputs se passent comme des arguments du bloc &lt;code&gt;module&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Les outputs se référencent avec &lt;code&gt;module.&amp;lt;nom&amp;gt;.&amp;lt;output&amp;gt;&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;portée-des-variables&#34;&gt;&lt;a href=&#34;#port%c3%a9e-des-variables&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Portée des variables&#xA;&lt;/h2&gt;&lt;p&gt;Une variable ou un local défini dans un module n&amp;rsquo;est &lt;strong&gt;pas&lt;/strong&gt; automatiquement visible dans les autres modules, parent ou enfant : chaque module a sa propre portée. Pour faire transiter une valeur :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Du parent vers l&amp;rsquo;enfant : passer un input au bloc &lt;code&gt;module&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;De l&amp;rsquo;enfant vers le parent : déclarer un &lt;code&gt;output&lt;/code&gt; dans l&amp;rsquo;enfant, puis le référencer via &lt;code&gt;module.&amp;lt;nom&amp;gt;.&amp;lt;output&amp;gt;&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Entre deux modules enfants : faire remonter la valeur au parent via un output, puis la repasser en input à l&amp;rsquo;autre module.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Il n&amp;rsquo;existe pas de variable globale partagée implicitement entre modules.&lt;/p&gt;&#xA;&lt;h2 id=&#34;registre-public-de-modules&#34;&gt;&lt;a href=&#34;#registre-public-de-modules&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Registre public de modules&#xA;&lt;/h2&gt;&lt;p&gt;Le &lt;a class=&#34;link&#34; href=&#34;https://registry.terraform.io/browse/modules&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Terraform Registry&lt;/a&gt; héberge des modules publics, identifiés par &lt;code&gt;&amp;lt;NAMESPACE&amp;gt;/&amp;lt;NOM&amp;gt;/&amp;lt;PROVIDER&amp;gt;&lt;/code&gt; (ex. &lt;code&gt;terraform-aws-modules/vpc/aws&lt;/code&gt;). Chaque module y expose sa documentation, ses inputs/outputs et l&amp;rsquo;historique de ses versions. Les modules &lt;strong&gt;verified&lt;/strong&gt; sont validés par HashiCorp ou un partenaire.&lt;/p&gt;&#xA;&lt;h2 id=&#34;versionning-des-modules&#34;&gt;&lt;a href=&#34;#versionning-des-modules&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Versionning des modules&#xA;&lt;/h2&gt;&lt;p&gt;Pour les sources de registre, l&amp;rsquo;argument &lt;code&gt;version&lt;/code&gt; accepte des contraintes :&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Opérateur&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Effet&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;=&lt;/code&gt; (ou rien)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Version exacte&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;!=&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Exclut une version&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Comparaison&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;~&amp;gt;&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Autorise seulement le dernier composant à incrémenter (ex. &lt;code&gt;~&amp;gt; 2.1&lt;/code&gt; autorise &lt;code&gt;2.1.x&lt;/code&gt; mais pas &lt;code&gt;2.2&lt;/code&gt;)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;consul&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  source&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hashicorp/consul/aws&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;~&amp;gt; 0.1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fixer une version évite qu&amp;rsquo;une mise à jour du module casse la configuration lors d&amp;rsquo;un prochain &lt;code&gt;terraform init&lt;/code&gt;. Sans contrainte, Terraform utilise la dernière version disponible.&lt;/p&gt;&#xA;&lt;h2 id=&#34;ce-que-je-retiens&#34;&gt;&lt;a href=&#34;#ce-que-je-retiens&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce que je retiens&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Un module = un répertoire de fichiers &lt;code&gt;.tf&lt;/code&gt;&lt;/strong&gt; : la configuration racine est elle-même un module.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Seules les sources de registre supportent le versionning&lt;/strong&gt; : un chemin local ou une source git suit le cycle de vie du code parent.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Pas de portée globale&lt;/strong&gt; : toute communication entre modules passe explicitement par des inputs et des outputs.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Prochaine étape de la série : le state management.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #4 — Terraform Configuration</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-configuration/</link>
            <pubDate>Mon, 17 Aug 2026 12:56:18 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-configuration/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-configuration/module4.png&#34; alt=&#34;Featured image of post Terraform Associate #4 — Terraform Configuration&#34; /&gt;&lt;p&gt;Suite de ma série sur la certification &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt;, après &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-core-workflow/&#34; &gt;le module sur le workflow&lt;/a&gt;. Le quatrième objectif de l&amp;rsquo;exam guide, &amp;ldquo;Read and write configuration&amp;rdquo;, est le plus dense. Celui-ci couvre les resources, les data sources, le système de types et les expressions conditionnelles, ainsi que la gestion des sensitive data.&lt;/p&gt;&#xA;&lt;h2 id=&#34;resources&#34;&gt;&lt;a href=&#34;#resources&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Resources&#xA;&lt;/h2&gt;&lt;p&gt;Le bloc &lt;code&gt;resource&lt;/code&gt; est l&amp;rsquo;unité de base de la configuration : c&amp;rsquo;est lui qui déclare une ressource gérée par Terraform (créée, modifiée et détruite selon le state).&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;aws_instance&amp;#34; &amp;#34;web&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  ami&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ami-0abcd1234&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  instance_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;t3.micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Les types de ressources disponibles dépendent des providers installés.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;aws_instance&lt;/code&gt; est le &lt;strong&gt;type&lt;/strong&gt; de ressource, &lt;code&gt;web&lt;/code&gt; est le &lt;strong&gt;nom local&lt;/strong&gt; : ensemble ils forment l&amp;rsquo;adresse &lt;code&gt;aws_instance.web&lt;/code&gt;, utilisée pour y référer ailleurs dans la configuration ou en CLI (&lt;code&gt;terraform state show aws_instance.web&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Les &lt;strong&gt;méta-arguments&lt;/strong&gt; s&amp;rsquo;appliquent à n&amp;rsquo;importe quel type de resource, indépendamment du provider.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Ils déterminent comment Terraform crée et gère la ressource, par exemple :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;count&lt;/code&gt; : crée N instances de la ressource, indexées (&lt;code&gt;aws_instance.web[0]&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;for_each&lt;/code&gt; : crée une instance par élément d&amp;rsquo;une map ou d&amp;rsquo;un set, indexées par clé (&lt;code&gt;aws_instance.web[&amp;quot;a&amp;quot;]&lt;/code&gt;) — plus robuste que &lt;code&gt;count&lt;/code&gt; quand la liste peut changer, car ça évite de décaler les index existants.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;depends_on&lt;/code&gt; : force une dépendance explicite quand Terraform ne peut pas la déduire des références entre arguments.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;lifecycle&lt;/code&gt; : bloc imbriqué pour affiner le comportement (&lt;code&gt;create_before_destroy&lt;/code&gt;, &lt;code&gt;prevent_destroy&lt;/code&gt;, &lt;code&gt;ignore_changes&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;data-sources&#34;&gt;&lt;a href=&#34;#data-sources&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Data sources&#xA;&lt;/h2&gt;&lt;p&gt;Terraform peut aller chercher des données auprès d&amp;rsquo;un large éventail de data sources : API, autres workspaces Terraform, outputs de fonctions&amp;hellip; Ce fetch dynamique rend la configuration plus flexible, mais ne crée ni ne modifie aucune ressource.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;aws_ami&amp;#34; &amp;#34;web&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  most_recent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  owners&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;amazon&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;filter&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    name&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    values&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;amzn2-ami-hvm-*-x86_64-gp2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;aws_instance&amp;#34; &amp;#34;web&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  ami&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;aws_ami&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;web&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;id&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  instance_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;t3.micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Terraform tente d&amp;rsquo;interroger les data sources dès la phase de plan, mais peut différer la lecture à la phase d&amp;rsquo;apply selon la configuration.&lt;/li&gt;&#xA;&lt;li&gt;Ajouter un argument &lt;code&gt;depends_on&lt;/code&gt; à un bloc data force Terraform à différer la lecture jusqu&amp;rsquo;à l&amp;rsquo;apply.&lt;/li&gt;&#xA;&lt;li&gt;On peut ajouter des blocs &lt;code&gt;precondition&lt;/code&gt; et &lt;code&gt;postcondition&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;On peut ajouter les méta-arguments &lt;code&gt;count&lt;/code&gt; et &lt;code&gt;for_each&lt;/code&gt; aux blocs data pour créer plusieurs instances de la data source.&lt;/li&gt;&#xA;&lt;li&gt;La syntaxe &lt;code&gt;data.&amp;lt;TYPE&amp;gt;.&amp;lt;LABEL&amp;gt;.&amp;lt;ATTRIBUTE&amp;gt;&lt;/code&gt; permet de référencer les attributs d&amp;rsquo;une data resource ailleurs dans la configuration.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;types&#34;&gt;&lt;a href=&#34;#types&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Types&#xA;&lt;/h2&gt;&lt;p&gt;Terraform a son propre système de types, utilisé notamment pour contraindre les variables (&lt;code&gt;variable &amp;quot;x&amp;quot; { type = ... }&lt;/code&gt;) et pour typer les valeurs manipulées dans la configuration.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Primitifs&lt;/strong&gt; : &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Collections&lt;/strong&gt; (éléments d&amp;rsquo;un seul type) : &lt;code&gt;list(type)&lt;/code&gt;, &lt;code&gt;set(type)&lt;/code&gt;, &lt;code&gt;map(type)&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Structurels&lt;/strong&gt; (éléments de types différents, structure fixe) : &lt;code&gt;object({ ... })&lt;/code&gt;, &lt;code&gt;tuple([...])&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;instance_type&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;t3.micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;tags&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;network&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    cidr_block&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    az_count&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;number&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Terraform effectue des conversions implicites quand c&amp;rsquo;est possible (une &lt;code&gt;list&lt;/code&gt; sans type déclaré est inférée, un &lt;code&gt;number&lt;/code&gt; peut être converti en &lt;code&gt;string&lt;/code&gt; dans une interpolation), mais déclarer le &lt;code&gt;type&lt;/code&gt; explicitement sur les variables reste la meilleure protection contre une valeur mal formée passée en entrée d&amp;rsquo;un module.&lt;/p&gt;&#xA;&lt;h2 id=&#34;références&#34;&gt;&lt;a href=&#34;#r%c3%a9f%c3%a9rences&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Références&#xA;&lt;/h2&gt;&lt;p&gt;On peut référencer les ressources dans notre configuration de plusieurs façons.&lt;/p&gt;&#xA;&lt;h3 id=&#34;références-de-ressources&#34;&gt;&lt;a href=&#34;#r%c3%a9f%c3%a9rences-de-ressources&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Références de ressources&#xA;&lt;/h3&gt;&lt;p&gt;Une adresse de ressource :&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;&lt;code&gt;[chemin de module][spec de ressource]&lt;/code&gt;&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;Chemin de module&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;module.nom_module[index de module]&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;Chemin de module complexe&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;module.foo[0].module.bar[&amp;ldquo;a&amp;rdquo;]&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;Chemin de spec de ressource&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;type_de_ressource.nom_ressource[index d&amp;rsquo;instance]&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;valeurs-pas-encore-connues&#34;&gt;&lt;a href=&#34;#valeurs-pas-encore-connues&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Valeurs pas encore connues&#xA;&lt;/h3&gt;&lt;p&gt;Quand Terraform planifie des changements pour appliquer la configuration, certaines valeurs ne peuvent pas être renseignées immédiatement car elles sont décidées dynamiquement par le système distant.&lt;/p&gt;&#xA;&lt;p&gt;Ces valeurs inconnues apparaissent dans la sortie de &lt;code&gt;terraform plan&lt;/code&gt; sous la forme &lt;code&gt;(known after apply)&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;variables--outputs&#34;&gt;&lt;a href=&#34;#variables--outputs&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Variables &amp;amp; outputs&#xA;&lt;/h2&gt;&lt;p&gt;Les modules Terraform communiquent entre eux via des inputs et des outputs.&#xA;Les variables permettent de paramétrer un module pour que d&amp;rsquo;autres utilisateurs puissent fournir des valeurs personnalisées au runtime.&lt;/p&gt;&#xA;&lt;h3 id=&#34;outputs&#34;&gt;&lt;a href=&#34;#outputs&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Outputs&#xA;&lt;/h3&gt;&lt;p&gt;Ils exposent des données d&amp;rsquo;un module, permettant d&amp;rsquo;exporter des informations sur l&amp;rsquo;infrastructure. La valeur d&amp;rsquo;un bloc output s&amp;rsquo;apparente à une valeur de retour dans d&amp;rsquo;autres langages de programmation.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;instance_public_ip&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;IP publique de l&amp;#39;instance web&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  value&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;aws_instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;web&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;public_ip&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;locals&#34;&gt;&lt;a href=&#34;#locals&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Locals&#xA;&lt;/h3&gt;&lt;p&gt;Les locals permettent de définir et réutiliser des expressions au sein d&amp;rsquo;un module.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;locals&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  name_prefix&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.project}-${var.environment}&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  common_tags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    project&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;project&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    env&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;environment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;aws_instance&amp;#34; &amp;#34;web&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  ami&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ami-0abcd1234&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  instance_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;t3.micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  tags&lt;/span&gt;          &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;common_tags&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;types-complexes&#34;&gt;&lt;a href=&#34;#types-complexes&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Types complexes&#xA;&lt;/h2&gt;&lt;p&gt;Un type complexe regroupe plusieurs valeurs en une seule.&lt;/p&gt;&#xA;&lt;h3 id=&#34;collection&#34;&gt;&lt;a href=&#34;#collection&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Collection&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;list(...)&lt;/code&gt; : une séquence de valeurs identifiées par des entiers consécutifs à partir de zéro.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;map(...)&lt;/code&gt; : une collection de valeurs où chacune est identifiée par un label de type string.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;set(...)&lt;/code&gt; : une collection de valeurs uniques, sans identifiant secondaire ni ordre.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;azs&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eu-west-1a&amp;#34;, &amp;#34;eu-west-1b&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;tags&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt; { env&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt; &amp;#34;prod&amp;#34;, team&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;infra&amp;#34;&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;allowed_ports&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;443&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;types-structurels&#34;&gt;&lt;a href=&#34;#types-structurels&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Types structurels&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;object(...)&lt;/code&gt; : un ensemble d&amp;rsquo;attributs nommés ayant chacun leur propre type (ex : &lt;code&gt;object({ name=string, age=number })&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;tuple(...)&lt;/code&gt; : une séquence d&amp;rsquo;éléments identifiés par des entiers consécutifs à partir de zéro, chaque élément ayant son propre type (ex : &lt;code&gt;tuple([string, number, bool])&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;network&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    cidr_block&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    az_count&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;number&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    cidr_block&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    az_count&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;any&#34;&gt;&lt;a href=&#34;#any&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Any&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;any&lt;/code&gt; est rarement le bon type à utiliser. Toujours spécifier le type exact, sauf en cas de données réellement dynamiques.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;validation-de-la-configuration&#34;&gt;&lt;a href=&#34;#validation-de-la-configuration&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Validation de la configuration&#xA;&lt;/h2&gt;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;terraform validate&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;La validation permet de vérifier que la configuration Terraform fonctionne comme prévu.&lt;/p&gt;&#xA;&lt;h3 id=&#34;moyens-de-validation&#34;&gt;&lt;a href=&#34;#moyens-de-validation&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Moyens de validation&#xA;&lt;/h3&gt;&lt;p&gt;Terraform propose plusieurs moyens de valider la configuration :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Les validations de variables d&amp;rsquo;input vérifient les paramètres de la configuration au moment du plan.&lt;/li&gt;&#xA;&lt;li&gt;Les preconditions s&amp;rsquo;assurent qu&amp;rsquo;une resource, data source ou output individuel respecte les exigences avant que Terraform ne tente de la créer.&lt;/li&gt;&#xA;&lt;li&gt;Les postconditions vérifient que Terraform a produit les resources et data sources avec les propriétés attendues.&lt;/li&gt;&#xA;&lt;li&gt;Les checks permettent de valider que l&amp;rsquo;infrastructure se comporte comme prévu sans bloquer les opérations Terraform selon leur résultat.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;aws_instance&amp;#34; &amp;#34;web&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  ami&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ami-0abcd1234&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  instance_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;t3.micro&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;lifecycle&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;precondition&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      condition&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt; data.aws_ami.web.architecture&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;x86_64&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      error_message&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#39;AMI doit être en x86_64.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;postcondition&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      condition&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt; self.public_ip !&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      error_message&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#39;instance doit avoir une IP publique.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;check&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;site_up&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http&amp;#34; &amp;#34;homepage&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://${aws_instance.web.public_ip}&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;assert&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    condition&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt; data.http.homepage.status_code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;200&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    error_message&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Le site ne répond pas en HTTP 200.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;checks&#34;&gt;&lt;a href=&#34;#checks&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Checks&#xA;&lt;/h3&gt;&lt;p&gt;Le bloc check sert à valider l&amp;rsquo;infrastructure en dehors du cycle de vie habituel des ressources.&#xA;Il s&amp;rsquo;exécute en dernière étape d&amp;rsquo;un plan ou d&amp;rsquo;un apply, une fois que Terraform a planifié ou provisionné l&amp;rsquo;infrastructure. Quand l&amp;rsquo;assertion d&amp;rsquo;un bloc check échoue, Terraform émet un warning et poursuit l&amp;rsquo;opération en cours.&lt;/p&gt;&#xA;&lt;p&gt;Il permet de :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Valider des resources, data sources, variables ou outputs de la configuration.&lt;/li&gt;&#xA;&lt;li&gt;Valider le comportement de l&amp;rsquo;infrastructure dans son ensemble.&lt;/li&gt;&#xA;&lt;li&gt;Vérifier la configuration de l&amp;rsquo;infrastructure sans bloquer les opérations.&lt;/li&gt;&#xA;&lt;li&gt;Effectuer une validation continue dans HCP Terraform.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;workflow-de-validation&#34;&gt;&lt;a href=&#34;#workflow-de-validation&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Workflow de validation&#xA;&lt;/h3&gt;&lt;p&gt;Terraform valide les différents aspects de la configuration le plus tôt possible. En général, l&amp;rsquo;ordre d&amp;rsquo;exécution est le suivant :&lt;/p&gt;&#xA;&lt;pre class=&#34;mermaid&#34; style=&#34;visibility:hidden&#34;&gt;flowchart TD&#xA;    A[Validations de variables d&#39;entrée] --&gt; B[Génération du plan]&#xA;    B --&gt; C[Preconditions]&#xA;    C --&gt; D[Création / modification de la resource, data source ou output]&#xA;    D --&gt; E[Postconditions]&#xA;    E --&gt; F[Apply terminé]&#xA;    F --&gt; G[Checks]&#xA;    G -.-&gt;|HCP Terraform| H[Health assessments périodiques]&lt;/pre&gt;&lt;h2 id=&#34;gérer-les-données-sensibles&#34;&gt;&lt;a href=&#34;#g%c3%a9rer-les-donn%c3%a9es-sensibles&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Gérer les données sensibles&#xA;&lt;/h2&gt;&lt;p&gt;Terraform peut avoir besoin d&amp;rsquo;accéder à des données sensibles (credentials cloud, tokens API, autres secrets) pour provisionner l&amp;rsquo;infrastructure.&#xA;Terraform stocke le state dans un fichier en clair, qui inclut toute valeur secrète définie dans la configuration.&lt;/p&gt;&#xA;&lt;h3 id=&#34;argument-sensitive&#34;&gt;&lt;a href=&#34;#argument-sensitive&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Argument sensitive&#xA;&lt;/h3&gt;&lt;p&gt;L&amp;rsquo;argument &lt;code&gt;sensitive&lt;/code&gt; sur un bloc variable ou output permet de masquer ces valeurs dans les logs du CLI Terraform et dans l&amp;rsquo;UI HCP Terraform.&lt;/p&gt;&#xA;&lt;h3 id=&#34;argument-ephemeral&#34;&gt;&lt;a href=&#34;#argument-ephemeral&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Argument ephemeral&#xA;&lt;/h3&gt;&lt;p&gt;Les valeurs ephemeral sont disponibles au runtime d&amp;rsquo;une opération, mais Terraform les omet des fichiers de state et de plan.&lt;/p&gt;&#xA;&lt;h3 id=&#34;quand-les-utiliser-&#34;&gt;&lt;a href=&#34;#quand-les-utiliser-&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Quand les utiliser ?&#xA;&lt;/h3&gt;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;code&gt;sensitive&lt;/code&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;code&gt;ephemeral&lt;/code&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Où l&amp;rsquo;utiliser&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Bloc &lt;code&gt;variable&lt;/code&gt; ou &lt;code&gt;output&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Bloc &lt;code&gt;variable&lt;/code&gt;, output d&amp;rsquo;un module enfant, bloc &lt;code&gt;ephemeral&lt;/code&gt;, argument write-only, &lt;code&gt;provider&lt;/code&gt;, &lt;code&gt;provisioner&lt;/code&gt;/&lt;code&gt;connection&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Effet sur le state/plan&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Reste dans le state, mais masqué dans les logs CLI et l&amp;rsquo;UI HCP Terraform&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Jamais persisté dans le state ni le plan&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Effet sur l&amp;rsquo;affichage&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Valeur remplacée par &lt;code&gt;(sensitive value)&lt;/code&gt; dans le plan/apply&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Valeur disponible uniquement au runtime de l&amp;rsquo;opération&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Portée d&amp;rsquo;usage&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Utilisable partout où la variable/output est référencé&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Restreint aux contextes ephemeral listés ci-dessus&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Cas d&amp;rsquo;usage typique&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Mot de passe affiché dans un output&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Token temporaire passé à un provider ou une resource&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h3 id=&#34;arguments-write-only&#34;&gt;&lt;a href=&#34;#arguments-write-only&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Arguments write-only&#xA;&lt;/h3&gt;&lt;p&gt;Les arguments write-only permettent de passer de façon sécurisée des valeurs temporaires aux managed resources de Terraform pendant une opération, sans les persister dans le state ou les fichiers de plan.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;aws_db_instance&amp;#34; &amp;#34;db&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  identifier&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;app-db&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  password_wo&lt;/span&gt;            &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;db_password&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  password_wo_version&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;db_password&amp;#34;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  ephemeral&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;bonnes-pratiques-de-sécurité&#34;&gt;&lt;a href=&#34;#bonnes-pratiques-de-s%c3%a9curit%c3%a9&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Bonnes pratiques de sécurité&#xA;&lt;/h3&gt;&lt;p&gt;Si des valeurs sensibles sont stockées dans un fichier de state, il est recommandé de mettre en place des mesures de sécurité supplémentaires :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Stocker le state à distance.&lt;/li&gt;&#xA;&lt;li&gt;Chiffrer le state au repos.&lt;/li&gt;&#xA;&lt;li&gt;Utiliser des contrôles d&amp;rsquo;accès pour limiter qui peut accéder au state.&lt;/li&gt;&#xA;&lt;li&gt;Utiliser des logs d&amp;rsquo;audit pour tracer les accès au state dans le temps.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;ce-que-je-retiens&#34;&gt;&lt;a href=&#34;#ce-que-je-retiens&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce que je retiens&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;count&lt;/code&gt; vs &lt;code&gt;for_each&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;for_each&lt;/code&gt; évite le décalage d&amp;rsquo;index quand la liste change, à privilégier dès que les éléments sont identifiables par une clé stable.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Preconditions, postconditions et checks&lt;/strong&gt; ne servent pas la même chose : les deux premières bloquent le plan/apply sur une resource précise, les checks valident l&amp;rsquo;infrastructure globalement sans bloquer.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;sensitive&lt;/code&gt; masque l&amp;rsquo;affichage, &lt;code&gt;ephemeral&lt;/code&gt; évite la persistance&lt;/strong&gt; : seul &lt;code&gt;ephemeral&lt;/code&gt; garantit qu&amp;rsquo;une valeur n&amp;rsquo;atterrit jamais dans le state ou le plan.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Prochaine étape de la série : les modules.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #3 — Core Terraform Workflow</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-core-workflow/</link>
            <pubDate>Sun, 16 Aug 2026 16:53:36 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-core-workflow/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-core-workflow/module3.png&#34; alt=&#34;Featured image of post Terraform Associate #3 — Core Terraform Workflow&#34; /&gt;&lt;p&gt;Suite de ma série sur la certification &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt;, après &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-fundamentals/&#34; &gt;le module sur les providers et le state&lt;/a&gt;. Le troisième objectif de l&amp;rsquo;exam guide s&amp;rsquo;intitule &amp;ldquo;Core Terraform workflow&amp;rdquo;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;le-cycle-write-plan-apply&#34;&gt;&lt;a href=&#34;#le-cycle-write-plan-apply&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Le cycle Write, Plan, Apply&#xA;&lt;/h2&gt;&lt;p&gt;Le workflow Terraform &amp;ldquo;de base&amp;rdquo; (un seul développeur, sans HCP Terraform ni CI) tient en trois étapes qui se répètent :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Write&lt;/strong&gt; : j&amp;rsquo;écris ou je modifie la configuration HCL.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Plan&lt;/strong&gt; : Terraform compare la configuration au state et à l&amp;rsquo;infrastructure réelle, puis affiche le diff des actions qu&amp;rsquo;il compte effectuer.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Apply&lt;/strong&gt; : Terraform exécute ce plan et met à jour le state en conséquence.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;terraform-init&#34;&gt;&lt;a href=&#34;#terraform-init&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;terraform init&#xA;&lt;/h2&gt;&lt;p&gt;Première commande à lancer dans un nouveau répertoire de configuration, ou après avoir ajouté un nouveau provider/module :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Télécharge les providers déclarés dans &lt;code&gt;required_providers&lt;/code&gt; et les modules référencés, puis met à jour le fichier de lock (vu dans le &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-fundamentals/#verrouillage-des-d%c3%a9pendances-dependency-lock&#34; &gt;module précédent&lt;/a&gt;).&lt;/li&gt;&#xA;&lt;li&gt;Configure le backend (local par défaut, ou distant s&amp;rsquo;il est défini).&lt;/li&gt;&#xA;&lt;li&gt;Idempotente : la relancer sur un répertoire déjà initialisé ne casse rien, c&amp;rsquo;est même le réflexe à avoir après un &lt;code&gt;git pull&lt;/code&gt; qui touche aux versions de providers.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform init&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;terraform-fmt-et-terraform-validate&#34;&gt;&lt;a href=&#34;#terraform-fmt-et-terraform-validate&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;terraform fmt et terraform validate&#xA;&lt;/h2&gt;&lt;p&gt;Deux commandes rapides à passer avant de committer, qui ne touchent ni au state ni à l&amp;rsquo;infrastructure :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;terraform fmt&lt;/code&gt; reformate les fichiers &lt;code&gt;.tf&lt;/code&gt; selon la convention de style canonique (indentation, alignement des &lt;code&gt;=&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;terraform validate&lt;/code&gt; vérifie que la configuration est syntaxiquement correcte et cohérente en interne (types, arguments requis, références). Elle ne contacte pas le provider et ne sait donc pas si une ressource existe déjà ou si les credentials sont valides.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform fmt -recursive&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform validate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;terraform-plan&#34;&gt;&lt;a href=&#34;#terraform-plan&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;terraform plan&#xA;&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est l&amp;rsquo;étape qui rend Terraform prévisible : avant de toucher à quoi que ce soit, il annonce ce qu&amp;rsquo;il va faire.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Compare la configuration, le state, et l&amp;rsquo;état réel de l&amp;rsquo;infrastructure via des appels en lecture au provider.&lt;/li&gt;&#xA;&lt;li&gt;Affiche un diff coloré : &lt;code&gt;+&lt;/code&gt; création, &lt;code&gt;-&lt;/code&gt; destruction, &lt;code&gt;~&lt;/code&gt; mise à jour, et parfois &lt;code&gt;-/+&lt;/code&gt; (destroy puis recreate, quand un attribut ne peut pas être modifié en place).&lt;/li&gt;&#xA;&lt;li&gt;Peut être sauvegardé dans un fichier avec &lt;code&gt;-out&lt;/code&gt;, pour garantir que l&amp;rsquo;&lt;code&gt;apply&lt;/code&gt; qui suit exécute exactement ce plan et rien d&amp;rsquo;autre (important en CI, où le code peut changer entre les deux étapes).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform plan -out&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;tfplan&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;terraform-apply&#34;&gt;&lt;a href=&#34;#terraform-apply&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;terraform apply&#xA;&lt;/h2&gt;&lt;p&gt;Exécute les actions du plan et persiste le résultat dans le state.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Sans fichier de plan en argument, &lt;code&gt;apply&lt;/code&gt; recalcule un plan et demande une confirmation interactive (&lt;code&gt;yes&lt;/code&gt;) avant d&amp;rsquo;exécuter.&lt;/li&gt;&#xA;&lt;li&gt;Avec un fichier de plan (&lt;code&gt;terraform apply tfplan&lt;/code&gt;), aucune confirmation n&amp;rsquo;est demandée : c&amp;rsquo;est le mode utilisé en CI/CD, après une revue humaine du plan affiché en amont.&lt;/li&gt;&#xA;&lt;li&gt;Terraform ordonne les créations/modifications/destructions selon le graphe de dépendances qu&amp;rsquo;il construit à partir de la configuration, pas selon l&amp;rsquo;ordre d&amp;rsquo;écriture des blocs.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform apply tfplan&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;terraform-destroy&#34;&gt;&lt;a href=&#34;#terraform-destroy&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;terraform destroy&#xA;&lt;/h2&gt;&lt;p&gt;Détruit toutes les ressources gérées par le state courant.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Fonctionne comme un &lt;code&gt;apply&lt;/code&gt; dont le plan ne contient que des destructions.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;-target&lt;/code&gt; permet de limiter la portée à une ressource précise, mais c&amp;rsquo;est un outil de dépannage ponctuel, pas une pratique à généraliser : il casse la vision globale du plan et peut laisser des ressources dans un état incohérent avec la configuration.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;terraform destroy&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ce-quil-faut-retenir&#34;&gt;&lt;a href=&#34;#ce-quil-faut-retenir&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce qu&amp;rsquo;il faut retenir&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;plan&lt;/code&gt; avant &lt;code&gt;apply&lt;/code&gt; n&amp;rsquo;est pas optionnel&lt;/strong&gt; : c&amp;rsquo;est la seule étape qui donne une visibilité sur ce qui va changer avant que ça ne change réellement.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;-out&lt;/code&gt; transforme un plan en contrat&lt;/strong&gt; : ce qui a été revu est exactement ce qui sera appliqué, ce qui est indispensable dès qu&amp;rsquo;un pipeline CI s&amp;rsquo;intercale entre la revue humaine et l&amp;rsquo;exécution.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;fmt&lt;/code&gt; et &lt;code&gt;validate&lt;/code&gt; sont des commandes de formattage et validation syntaxique, l&amp;rsquo;infrastructure sous jacente n&amp;rsquo;est pas analysée.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Prochaine étape de la série : la configuration Terraform.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #2 — Terraform fundamentals</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-fundamentals/</link>
            <pubDate>Sun, 16 Aug 2026 13:48:17 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-fundamentals/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-fundamentals/module2.png&#34; alt=&#34;Featured image of post Terraform Associate #2 — Terraform fundamentals&#34; /&gt;&lt;p&gt;Suite de ma série sur la certification &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/tags/terraformassociate/&#34; &gt;Terraform Associate&lt;/a&gt;, après &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-infrastructure-as-code/&#34; &gt;le premier module sur l&amp;rsquo;Infrastructure as Code&lt;/a&gt;. Le deuxième module de l&amp;rsquo;exam guide s&amp;rsquo;intitule &amp;ldquo;Terraform Fundamentals&amp;rdquo; : il s&amp;rsquo;agit de comprendre ce que sont les providers et comment le state fonctionne.&lt;/p&gt;&#xA;&lt;h2 id=&#34;les-providers&#34;&gt;&lt;a href=&#34;#les-providers&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Les providers&#xA;&lt;/h2&gt;&lt;p&gt;Terraform ne parle nativement à aucun cloud. Tout se fait via des &lt;strong&gt;providers&lt;/strong&gt; : des plugins qui traduisent le langage déclaratif HCL en appels API vers AWS, GCP, Azure, mais aussi Kubernetes, Cloudflare, Datadog, GitHub&amp;hellip; Le cœur de Terraform (le CLI, le state, le langage) reste identique quel que soit le provider utilisé.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Chaque provider ajoute un ensemble de types de ressources et/ou de data sources que Terraform peut gérer.&lt;/li&gt;&#xA;&lt;li&gt;Chaque type de ressource est implémenté par un provider ; sans providers, Terraform ne peut gérer aucun type d&amp;rsquo;infrastructure.&lt;/li&gt;&#xA;&lt;li&gt;Terraform exige un nom local unique pour chaque provider au sein d&amp;rsquo;un module.&lt;/li&gt;&#xA;&lt;li&gt;N&amp;rsquo;importe qui peut développer et distribuer ses propres providers Terraform&lt;/li&gt;&#xA;&lt;li&gt;Quand un provider est défini dans le module racine, Terraform transmet implicitement cette configuration à tous les modules enfants, afin que tous les modules utilisent la même configuration.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Ne pas confondre &lt;code&gt;required_providers&lt;/code&gt;et &lt;code&gt;provider&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;required_providers&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Sert uniquement à terraform init : source (adresse dans le registry) + contrainte de version, pour savoir quel plugin télécharger.&lt;/li&gt;&#xA;&lt;li&gt;Pas de credentials, pas de région, aucune logique d&amp;rsquo;exécution.&lt;/li&gt;&#xA;&lt;li&gt;Un seul bloc par module.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;provider&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Configure une instance réelle du provider : région, credentials, endpoints custom, etc.&lt;/li&gt;&#xA;&lt;li&gt;Peut apparaître plusieurs fois pour le même provider via alias (ex. déployer sur plusieurs régions AWS dans le même module).&lt;/li&gt;&#xA;&lt;li&gt;Sans lui, init fonctionne mais plan/apply échouera (ou retombera sur des credentials par défaut via variables d&amp;rsquo;env/CLI).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;dependency-lock&#34;&gt;&lt;a href=&#34;#dependency-lock&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Dependency lock&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;Le fichier lock ne suit que les dépendances des providers.&lt;/li&gt;&#xA;&lt;li&gt;Terraform crée ou met à jour automatiquement ce fichier à chaque exécution de &lt;code&gt;terraform init&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Ce fichier appartient à la configuration dans son ensemble, et non à chaque module pris séparément.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;comportement-dinstallation-des-dépendances&#34;&gt;&lt;a href=&#34;#comportement-dinstallation-des-d%c3%a9pendances&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Comportement d&amp;rsquo;installation des dépendances&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;Quand &lt;code&gt;terraform init&lt;/code&gt; installe les providers nécessaires à une configuration, Terraform prend en compte à la fois les contraintes de version de la configuration et celles déjà enregistrées dans le fichier de lock.&lt;/li&gt;&#xA;&lt;li&gt;Si un provider n&amp;rsquo;a pas encore de version enregistrée, Terraform choisit la version la plus récente qui respecte la contrainte, puis met à jour le fichier de lock avec ce choix.&lt;/li&gt;&#xA;&lt;li&gt;On peut forcer ce comportement avec l&amp;rsquo;option &lt;code&gt;-upgrade&lt;/code&gt; sur &lt;code&gt;terraform init&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;le-state--la-mémoire-de-terraform&#34;&gt;&lt;a href=&#34;#le-state--la-m%c3%a9moire-de-terraform&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Le state : la mémoire de Terraform&#xA;&lt;/h2&gt;&lt;p&gt;Le fichier &lt;code&gt;terraform.tfstate&lt;/code&gt; est ce qui permet à Terraform d&amp;rsquo;être déclaratif : c&amp;rsquo;est lui qui fait le lien entre la configuration HCL (ce que je veux) et les ressources réellement créées chez le fournisseur (ce qui existe). Sans state, Terraform ne pourrait pas savoir qu&amp;rsquo;un &lt;code&gt;aws_instance.web&lt;/code&gt; dans le code correspond à l&amp;rsquo;instance &lt;code&gt;i-0abc123&lt;/code&gt; déjà en place.&lt;/p&gt;&#xA;&lt;p&gt;Ses rôles concrets :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Mapping vers le monde réel.&lt;/strong&gt; Le state associe chaque ressource déclarée à un identifiant réel côté fournisseur, indispensable pour savoir quoi modifier ou détruire.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Metadata.&lt;/strong&gt; Il stocke aussi des informations que l&amp;rsquo;API du fournisseur n&amp;rsquo;expose pas toujours (dépendances entre ressources, par exemple), utiles pour calculer un plan correct.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Performance.&lt;/strong&gt; Pour de grosses infrastructures, relire l&amp;rsquo;état de centaines de ressources via l&amp;rsquo;API à chaque commande serait lent. Le state fait office de cache.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Collaboration.&lt;/strong&gt; En le stockant à distance (S3, GCS, Terraform Cloud&amp;hellip;) avec un mécanisme de lock, plusieurs personnes peuvent exécuter des &lt;code&gt;apply&lt;/code&gt; sans risquer d&amp;rsquo;écraser le travail des autres. C&amp;rsquo;est un point que j&amp;rsquo;avais déjà creusé en pratique dans mes articles sur &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/the-forge-infra-improved/&#34; &gt;the-forge-infra&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;state-distant-remote-state&#34;&gt;&lt;a href=&#34;#state-distant-remote-state&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;State distant (remote state)&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;Terraform écrit les données de state dans un espace de stockage distant, qui peut ensuite être partagé entre tous les membres d&amp;rsquo;une équipe. Terraform prend en charge le stockage du state dans HCP Terraform, HashiCorp Consul, Amazon S3, Azure Blob Storage, Google Cloud Storage, Alibaba Cloud OSS, et d&amp;rsquo;autres.&lt;/li&gt;&#xA;&lt;li&gt;Le state distant est implémenté par un backend, ou par HCP Terraform, tous deux configurables dans le module racine de la configuration.&lt;/li&gt;&#xA;&lt;li&gt;La data source &lt;code&gt;terraform_remote_state&lt;/code&gt; utilise le dernier snapshot de state d&amp;rsquo;un backend donné pour récupérer les valeurs de sortie (outputs) du module racine d&amp;rsquo;une autre configuration Terraform.&lt;/li&gt;&#xA;&lt;li&gt;Pour les backends distants les plus complets, Terraform peut aussi verrouiller le state afin d&amp;rsquo;empêcher des exécutions concurrentes sur le même state.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;ce-que-je-retiens&#34;&gt;&lt;a href=&#34;#ce-que-je-retiens&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce que je retiens&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;required_providers&lt;/code&gt; vs &lt;code&gt;provider&lt;/code&gt;&lt;/strong&gt; : le premier dit à &lt;code&gt;terraform init&lt;/code&gt; quoi télécharger (source, version), le second configure une instance réelle (région, credentials) et peut se dupliquer via des alias.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Le state n&amp;rsquo;est pas un détail d&amp;rsquo;implémentation&lt;/strong&gt; : c&amp;rsquo;est lui qui fait le lien entre le code HCL et les ressources réelles, sert de cache de métadonnées pour construire les plans, et permet le travail en équipe une fois stocké à distance avec un lock.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Le fichier de lock ne concerne que les providers&lt;/strong&gt; : il garantit des versions reproductibles à &lt;code&gt;init&lt;/code&gt;, indépendamment des modules.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Prochaine étape de la série : le workflow Terraform.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Terraform Associate #1 — Infrastructure as Code</title>
            <link>https://valerian-pyckaert.dev/posts/terraform-associate-infrastructure-as-code/</link>
            <pubDate>Sun, 16 Aug 2026 13:44:02 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/terraform-associate-infrastructure-as-code/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/terraform-associate-infrastructure-as-code/iac.png&#34; alt=&#34;Featured image of post Terraform Associate #1 — Infrastructure as Code&#34; /&gt;&lt;p&gt;Comme &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/posts/certification-terraform-associate/&#34; &gt;annoncé précédemment&lt;/a&gt;, je prépare la certification &lt;a class=&#34;link&#34; href=&#34;https://www.hashicorp.com/en/certification/terraform-associate&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Terraform Associate&lt;/a&gt;. Premier objectif de l&amp;rsquo;exam guide : &amp;ldquo;Understand Infrastructure as Code (IaC) concepts&amp;rdquo;. Avant de parler syntaxe HCL ou providers, il s&amp;rsquo;agit de poser les bases : qu&amp;rsquo;est-ce que l&amp;rsquo;IaC, et pourquoi ça a remplacé la gestion manuelle d&amp;rsquo;infrastructure.&lt;/p&gt;&#xA;&lt;h2 id=&#34;quest-ce-que-linfrastructure-as-code&#34;&gt;&lt;a href=&#34;#quest-ce-que-linfrastructure-as-code&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Qu&amp;rsquo;est-ce que l&amp;rsquo;Infrastructure as Code&#xA;&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;Infrastructure as Code, c&amp;rsquo;est décrire son infrastructure (serveurs, réseau, bases de données, permissions IAM&amp;hellip;) sous forme de fichiers texte versionnables, plutôt que de la construire à la main via une console web ou des commandes ad hoc.&lt;/p&gt;&#xA;&lt;p&gt;Ces fichiers deviennent la source de vérité : un outil (Terraform, mais aussi Pulumi, CloudFormation, Ansible&amp;hellip;) les lit et se charge de créer, modifier ou supprimer les ressources correspondantes chez le fournisseur cloud.&lt;/p&gt;&#xA;&lt;p&gt;Deux façons d&amp;rsquo;écrire cette description :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Impératif&lt;/strong&gt; : on décrit la suite d&amp;rsquo;étapes pour arriver au résultat (&amp;ldquo;crée un VPC, puis crée un subnet dedans, puis attache une route table&amp;hellip;&amp;rdquo;). C&amp;rsquo;est l&amp;rsquo;approche d&amp;rsquo;un script bash ou d&amp;rsquo;un playbook Ansible classique.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Déclaratif&lt;/strong&gt; : on décrit l&amp;rsquo;état final voulu (&amp;ldquo;je veux un VPC avec ce CIDR et ces subnets&amp;rdquo;), et l&amp;rsquo;outil calcule lui-même les actions nécessaires pour y parvenir. C&amp;rsquo;est l&amp;rsquo;approche de Terraform.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;L&amp;rsquo;approche déclarative est centrale pour comprendre Terraform : on ne lui dit jamais &amp;ldquo;crée ceci&amp;rdquo;, on lui dit &amp;ldquo;voici l&amp;rsquo;état que je veux&amp;rdquo;, et c&amp;rsquo;est le moteur (via le state et le plan) qui détermine le diff à appliquer.&lt;/p&gt;&#xA;&lt;h2 id=&#34;idempotence&#34;&gt;&lt;a href=&#34;#idempotence&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Idempotence&#xA;&lt;/h2&gt;&lt;p&gt;Une propriété qui découle directement du déclaratif : réappliquer la même configuration plusieurs fois de suite ne doit rien changer si l&amp;rsquo;infrastructure correspond déjà à l&amp;rsquo;état décrit. &lt;code&gt;terraform apply&lt;/code&gt; sur une configuration inchangée doit annoncer &amp;ldquo;No changes.&amp;rdquo; C&amp;rsquo;est ce qui rend l&amp;rsquo;IaC fiable en CI/CD : on peut la rejouer sans craindre de dupliquer des ressources ou de casser l&amp;rsquo;existant.&lt;/p&gt;&#xA;&lt;h2 id=&#34;pourquoi-liac-plutôt-que-le-clic-dans-une-console&#34;&gt;&lt;a href=&#34;#pourquoi-liac-plut%c3%b4t-que-le-clic-dans-une-console&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Pourquoi l&amp;rsquo;IaC plutôt que le clic dans une console&#xA;&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est la deuxième partie de l&amp;rsquo;objectif de l&amp;rsquo;exam guide : &amp;ldquo;Describe advantages of IaC patterns&amp;rdquo;. Ce qui m&amp;rsquo;a personnellement convaincu, avant même de penser à une certification :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Versioning et historique.&lt;/strong&gt; Chaque changement d&amp;rsquo;infra passe par un commit Git, avec un auteur, une date et (idéalement) une revue de code. Impossible d&amp;rsquo;obtenir ça avec des clics dans une console.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Collaboration.&lt;/strong&gt; Plusieurs personnes peuvent travailler sur la même infrastructure via des pull requests, sans se marcher dessus ni se demander &amp;ldquo;qui a changé ce security group hier soir&amp;rdquo;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Reproductibilité.&lt;/strong&gt; Recréer un environnement identique (staging, nouvelle région, nouveau client) devient une question de minutes, pas de jours de configuration manuelle.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Documentation vivante.&lt;/strong&gt; Le code Terraform décrit l&amp;rsquo;infrastructure telle qu&amp;rsquo;elle est réellement, contrairement à un wiki qui devient obsolète dès qu&amp;rsquo;on oublie de le mettre à jour.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Réduction de l&amp;rsquo;erreur humaine.&lt;/strong&gt; Un plan Terraform montre le diff avant application ; un clic malheureux dans une console, lui, ne prévient pas.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;ce-que-je-retiens&#34;&gt;&lt;a href=&#34;#ce-que-je-retiens&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Ce que je retiens&#xA;&lt;/h2&gt;&lt;p&gt;Ce premier module reste conceptuel, mais il pose un vocabulaire que je retrouverai tout au long de la certification : déclaratif, idempotence, state. Le module suivant s&amp;rsquo;attaque aux providers et au state.&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Objectif certification Terraform Associate</title>
            <link>https://valerian-pyckaert.dev/posts/certification-terraform-associate/</link>
            <pubDate>Sat, 15 Aug 2026 18:25:02 +0200</pubDate>
            <guid>https://valerian-pyckaert.dev/posts/certification-terraform-associate/</guid>
            <description>&lt;img src=&#34;https://valerian-pyckaert.dev/posts/certification-terraform-associate/projet_certif.png&#34; alt=&#34;Featured image of post Objectif certification Terraform Associate&#34; /&gt;&lt;p&gt;Terraform, je l&amp;rsquo;utilise quasiment au quotidien : que ce soit sur &lt;a class=&#34;link&#34; href=&#34;https://valerian-pyckaert.dev/categories/theforge/&#34; &gt;TheForge&lt;/a&gt; ou en entreprise, c&amp;rsquo;est l&amp;rsquo;outil que je manipule le plus après Kubernetes. Mais jusqu&amp;rsquo;ici, mes connaissances se sont construites au fil des besoins, projet après projet, sans jamais couvrir l&amp;rsquo;ensemble des concepts de façon structurée.&lt;/p&gt;&#xA;&lt;p&gt;Je me lance donc dans la préparation de la certification &lt;a class=&#34;link&#34; href=&#34;https://www.hashicorp.com/en/certification/terraform-associate&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;HashiCorp Certified: Terraform Associate&lt;/a&gt;. L&amp;rsquo;objectif n&amp;rsquo;est pas tant le badge en lui-même que de combler les angles morts : provider versioning, state management avancé, modules, workspaces, sont autant de sujets que j&amp;rsquo;utilise sans toujours en maîtriser toutes les subtilités.&lt;/p&gt;&#xA;&lt;h2 id=&#34;pourquoi-cette-certification&#34;&gt;&lt;a href=&#34;#pourquoi-cette-certification&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Pourquoi cette certification&#xA;&lt;/h2&gt;&lt;p&gt;Trois raisons principales m&amp;rsquo;ont poussé à me lancer :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Structurer des connaissances acquises en pratique.&lt;/strong&gt; Apprendre &amp;ldquo;sur le tas&amp;rdquo; laisse forcément des trous : on maîtrise ce dont on a eu besoin, pas nécessairement ce qui est important.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Valider mes acquis avec un référentiel externe.&lt;/strong&gt; Un examen impose un niveau d&amp;rsquo;exigence que l&amp;rsquo;auto-formation seule n&amp;rsquo;impose pas toujours.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Une certification reconnue dans l&amp;rsquo;écosystème DevOps/Cloud&lt;/strong&gt;, utile aussi bien pour mes projets personnels que pour mon activité professionnelle.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;comment-je-vais-morganiser&#34;&gt;&lt;a href=&#34;#comment-je-vais-morganiser&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Comment je vais m&amp;rsquo;organiser&#xA;&lt;/h2&gt;&lt;p&gt;Mon plan de préparation :&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Reprendre la &lt;a class=&#34;link&#34; href=&#34;https://developer.hashicorp.com/terraform/docs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;documentation officielle Terraform&lt;/a&gt; et l&amp;rsquo;&lt;a class=&#34;link&#34; href=&#34;https://developer.hashicorp.com/terraform/tutorials/certification-associate-tf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;exam guide&lt;/a&gt; point par point.&lt;/li&gt;&#xA;&lt;li&gt;Manipuler chaque concept dans un contexte concret, en m&amp;rsquo;appuyant sur mes projets existants (notamment &lt;a class=&#34;link&#34; href=&#34;https://github.com/Bernedotcom2312/theforge-infra&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;the-forge-infra&lt;/a&gt;) plutôt que sur des exemples jetables.&lt;/li&gt;&#xA;&lt;li&gt;M&amp;rsquo;entraîner sur des questions type examen pour identifier mes points faibles avant de passer le test.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;la-suite&#34;&gt;&lt;a href=&#34;#la-suite&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;La suite&#xA;&lt;/h2&gt;&lt;p&gt;Je partagerai mon parcours d&amp;rsquo;apprentissage dans de prochains articles : les notions qui m&amp;rsquo;ont surpris, les pièges classiques de l&amp;rsquo;examen, et ce que je retiens une fois la certification passée. Rendez-vous dans les prochains articles pour la suite de cette préparation.&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
