<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Denis</title>
    <description>The latest articles on DEV Community by Denis (@zidenis).</description>
    <link>https://dev.to/zidenis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2646255%2Faf061e7d-1fd2-4cc4-8a5d-6fe15e807c3f.jpeg</url>
      <title>DEV Community: Denis</title>
      <link>https://dev.to/zidenis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zidenis"/>
    <language>en</language>
    <item>
      <title>Terraform Cookbook: Development Environment Recipe</title>
      <dc:creator>Denis</dc:creator>
      <pubDate>Thu, 02 Jan 2025 22:32:40 +0000</pubDate>
      <link>https://dev.to/zidenis/terraform-cookbook-development-environment-recipe-3k57</link>
      <guid>https://dev.to/zidenis/terraform-cookbook-development-environment-recipe-3k57</guid>
      <description>&lt;p&gt;TLDR: This tutorial provides a step-by-step guide to setting up a complete Terraform development environment, including version management (tenv), documentation generation (terraform-docs), linting (TFLint), security scanning (Trivy, Checkov), pre-commit hooks, and others. We use a cookbook-style approach for easy understanding, but if you just want the command script to set up the environment, you can get it &lt;a href="https://github.com/zidenis/terraform-module-template-aws/blob/main/environment_setup.sh" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform Cookbook: Development Environment Recipe
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A quick and easy recipe to set up a killer development environment for writing Terraform modules. Tested on Linux Ubuntu 24.04.1 LTS for x86_64 architecture (should work on other debian-based systems. For other Linux distributions, some tweaks are required).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Building robust and secure infrastructure with Terraform requires more than just the terraform CLI. A well-equipped development environment is crucial for maximizing productivity, ensuring code quality, and preventing costly mistakes. This tutorial serves as your complete recipe for setting up a top-notch Terraform development environment. I'll guide you through installing and configuring essential tools. By the end of this tutorial, you will have a streamlined workflow, enabling you to focus on building infrastructure rather than managing complex configurations. We use a cookbook-style approach for easy understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ingredients:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Linux utilities (curl, jq, tar, unzip, git)&lt;/li&gt;
&lt;li&gt;tenv: &lt;a href="https://github.com/tofuutils/tenv" rel="noopener noreferrer"&gt;version manager for Terraform&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;terraform CLI: &lt;a href="https://developer.hashicorp.com/terraform/cli" rel="noopener noreferrer"&gt;HashiCorp's Terraform CLI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;terraform-docs: &lt;a href="https://github.com/terraform-docs/terraform-docs" rel="noopener noreferrer"&gt;tool for generating module documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TFLint: &lt;a href="https://github.com/terraform-linters/tflint" rel="noopener noreferrer"&gt;terraform linter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Trivy: &lt;a href="https://github.com/aquasecurity/trivy" rel="noopener noreferrer"&gt;security scanner for IaC and dependencies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;venv: &lt;a href="https://docs.python.org/3/library/venv.html" rel="noopener noreferrer"&gt;virtual environments for Python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pre-commit: &lt;a href="https://pre-commit.com" rel="noopener noreferrer"&gt;git hook manager&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pre-commit-terraform: &lt;a href="https://github.com/antonbabenko/pre-commit-terraform" rel="noopener noreferrer"&gt;terraform git hooks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Checkov: &lt;a href="https://github.com/bridgecrewio/checkov" rel="noopener noreferrer"&gt;static analysis for IaC&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;VSCode: &lt;a href="https://marketplace.visualstudio.com/items?itemName=4ops.terraform" rel="noopener noreferrer"&gt;code editor with Terraform extension&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preparation Steps:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Know Your Kitchen, VSCode.
&lt;/h3&gt;

&lt;p&gt;First things first, every chef needs a well-equipped kitchen. In our case, Visual Studio Code is our kitchen, the place where we'll craft all our infrastructure recipes. But a bare kitchen isn't enough. We need the right tools and appliances to prepare delicious dishes. That's where the &lt;a href="https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform" rel="noopener noreferrer"&gt;Terraform extension by Hashicorp&lt;/a&gt; comes in. The extension provides syntax highlighting, code completion, among other features.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Follow the [VSCode installation guide](https://code.visualstudio.com/docs/setup/linux) for other instalation methods.&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;curl

curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; vscode.deb  https://go.microsoft.com/fwlink/?LinkID&lt;span class="o"&gt;=&lt;/span&gt;760868

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; ./vscode.deb

code 
&lt;span class="c"&gt;# After VSCode launch, use Quick Open (Ctrl+P), paste the command "ext install HashiCorp.terraform" and press enter.&lt;/span&gt;
&lt;span class="c"&gt;# Or install the extension @id:HashiCorp.terraform using the VSCode GUI.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Equip Your Kitchen with  &lt;code&gt;tenv&lt;/code&gt;.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Manage multiple Terraform versions like a pro. Simplifies the management of multiple Terraform versions, ensuring compatibility with different projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Grab your Terraform version manager, &lt;code&gt;tenv&lt;/code&gt;. Every good chef needs a well-organized kitchen. When it comes to managing different versions of Terraform, &lt;code&gt;tenv&lt;/code&gt; will keep your environment neatly organized and easily accessible. It also supports OpenTofu, Terragrunt, and Atmos. Let's get it installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TENV_LATEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.github.com/repos/tofuutils/tenv/releases/latest | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.assets[] | select(.name | endswith("Linux_x86_64.tar.gz")) | .browser_download_url'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="nv"&gt;$TENV_LATEST&lt;/span&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/.tenv

&lt;span class="nb"&gt;tar &lt;/span&gt;xvzf &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TENV_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"tenv_v.*"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; ~/.tenv

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.tenv:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

tenv completion bash &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/.tenv/tenv_completion.bash

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'\n# tenv and terraform tools\nexport PATH="$HOME/.tenv:$PATH"\nsource $HOME/.tenv/tenv_completion.bash'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lines added to .bashrc ensure that &lt;code&gt;tenv&lt;/code&gt; is always available when we start cooking terraform modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Grab Your Trusty &lt;code&gt;terraform&lt;/code&gt; CLI Using &lt;code&gt;tenv&lt;/code&gt;.
&lt;/h3&gt;

&lt;p&gt;It's time to grab our most essential infrastructure cooking utensil, our pan: the &lt;code&gt;terraform&lt;/code&gt; CLI. This is the workhorse of our infrastructure kitchen – the pan we'll use to cook up all our infrastructure recipes. We'll use &lt;code&gt;tenv&lt;/code&gt; to fetch and install the perfect pan for the job. If you wish, use &lt;a href="https://opentofu.org/" rel="noopener noreferrer"&gt;Opentofu&lt;/a&gt;, which is an "more open" source altenative.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tenv terraform &lt;span class="nb"&gt;install

&lt;/span&gt;terraform &lt;span class="nt"&gt;-install-autocomplete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is like reaching into our neatly organized tools rack and selecting the perfect terraform CLI pan.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Compile Your Infrastructure Recipe Notebook With &lt;code&gt;terraform-docs&lt;/code&gt;.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Automatically generate documentation for your terraform modules (inputs, outputs, etc.).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A good chef keeps a detailed recipe notebook, documenting each dish's ingredients, instructions, and variations. In the world of infrastructure as code, terraform-docs is our tool to maintain recipe documents. It automatically generates documentation for our Terraform modules, neatly organizing inputs, outputs, and other important details. This ensures that anyone (including our future selves) can easily understand and use our infrastructure recipes. Let's add it to our kitchen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TDOC_LATEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.github.com/repos/terraform-docs/terraform-docs/releases/latest | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.assets[] | select(.name | endswith("linux-amd64.tar.gz")) | .browser_download_url'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="nv"&gt;$TDOC_LATEST&lt;/span&gt;

&lt;span class="nb"&gt;tar &lt;/span&gt;xzf &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TDOC_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"terraform-docs-.+"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; ~/.tenv terraform-docs

terraform-docs completion bash &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/.tenv/terraform-docs_completion.bash

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'\nsource $HOME/.tenv/terraform-docs_completion.bash'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.  Employ TFLint Quality Control.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A linter for Terraform code. Catch syntax errors, enforce standards, and keep your Terraform configs clean.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maintaining quality control is crucial. In the Terraform kitchen, &lt;code&gt;TFLint&lt;/code&gt; scans our Terraform code for syntax errors and potential issues, ensuring our code is sound. Let's add this to our kitchen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TFLINT_LATEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.github.com/repos/terraform-linters/tflint/releases/latest | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.assets[] | select(.name | endswith("tflint_linux_amd64.zip")) | .browser_download_url'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="nv"&gt;$TFLINT_LATEST&lt;/span&gt;

unzip &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TFLINT_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"tflint_linux.+"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; ~/.tenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/zidenis/terraform-module-template-aws/blob/main/.tflint.hcl" rel="noopener noreferrer"&gt;&lt;code&gt;.tflint.hcl&lt;/code&gt;&lt;/a&gt; file is the configuration file for TFLint. Its purpose is to define the rules, plugins, and configurations that TFLint will use when analyzing your Terraform code. This allows you to enforce best practices, identify issues, and customize the linter's behavior to align with your project requirements. The configuration I currently use for terraform AWS resources is like the bellow example.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample &lt;a href="https://github.com/zidenis/terraform-module-template-aws/blob/main/.tflint.hcl" rel="noopener noreferrer"&gt;&lt;code&gt;.tflint.hcl&lt;/code&gt;&lt;/a&gt; Configuration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;tflint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.54.0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;plugin&lt;/span&gt; &lt;span class="s2"&gt;"terraform"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;preset&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"all"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;plugin&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.36.0"&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github.com/terraform-linters/tflint-ruleset-aws"&lt;/span&gt;
  &lt;span class="nx"&gt;deep_check&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="s2"&gt;"aws_resource_missing_tags"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"env"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Double Strain Your Infrastructure Code With &lt;code&gt;Trivy&lt;/code&gt; And &lt;code&gt;Checkov&lt;/code&gt;.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Trivy scan your IaC files, container images, and dependencies for vulnerabilities. &lt;/p&gt;

&lt;p&gt;Checkov detects misconfigurations, security risks, and compliance violations in Terraform and other IaC templates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ensuring the safety of your code is paramount. You wouldn't want any unwanted bits sneaking into your dishes. Just as a chef uses strainers to remove impurities, we use &lt;code&gt;Trivy&lt;/code&gt; and &lt;code&gt;Checkov&lt;/code&gt; to filter out potential vulnerabilities and misconfigurations from our infrastructure code. Think of them as two different types of strainers, each catching different kinds of unwanted elements. Let's add them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TRIVY_LATEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.github.com/repos/aquasecurity/trivy/releases/latest | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.assets[] | select(.name | endswith("Linux-64bit.tar.gz")) | .browser_download_url'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="nv"&gt;$TRIVY_LATEST&lt;/span&gt;

&lt;span class="nb"&gt;tar &lt;/span&gt;xzf &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TRIVY_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"trivy_.+"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; ~/.tenv trivy

&lt;span class="c"&gt;# We are going to install checkov using python pip and venv&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3-pip python3.12-venv

python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv ~/.venv

&lt;span class="nb"&gt;source&lt;/span&gt; ~/.venv/bin/activate

pip &lt;span class="nb"&gt;install &lt;/span&gt;checkov
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, with both &lt;code&gt;Trivy&lt;/code&gt;  and &lt;code&gt;Checkov&lt;/code&gt; in our kitchen, we can confidently cook a safe and secure code. This double-straining approach provides a more comprehensive security check, catching both specific vulnerabilities and broader misconfigurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Set Up Your &lt;code&gt;pre-commit&lt;/code&gt; Kitchen Workflow Checklist
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Ensures consistent code quality by running checks (e.g., linting, formatting, security scans) before committing code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a busy kitchen, chefs rely on checklists and workflows to ensure every step is followed and no crucial task is missed. &lt;code&gt;pre-commit&lt;/code&gt; acts as our kitchen workflow checklist, ensuring we systematically employ all our quality control and tools (like &lt;code&gt;TFLint&lt;/code&gt;, &lt;code&gt;Trivy&lt;/code&gt;, and &lt;code&gt;Checkov&lt;/code&gt;) before we "serve" (commit) our infrastructure code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pre-commit&lt;/code&gt; uses git hooks, which are scripts that run automatically at specific points in the Git workflow. In this case, we're going to use &lt;code&gt;pre-commit&lt;/code&gt; hooks, which run before each git commit. This ensures that our code is always checked before it's added to the project's history. Let's set up our kitchen workflow checklist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.venv/bin/activate

pip &lt;span class="nb"&gt;install &lt;/span&gt;pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have pre-commit installed, we'll configure it to use our quality control tools. The &lt;a href="https://github.com/zidenis/terraform-module-template-aws/blob/main/.pre-commit-config.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;&lt;/a&gt; file is the configuration file for the Pre-commit framework that define the pre-commit hook.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample &lt;a href="https://github.com/zidenis/terraform-module-template-aws/blob/main/.pre-commit-config.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;&lt;/a&gt; Configuration.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/antonbabenko/pre-commit-terraform&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1.96.2&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform_validate&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform_fmt&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform_tflint&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--args=--config=__GIT_WORKING_DIR__/.tflint.hcl&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform_trivy&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform_checkov&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;validate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Checkov"&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--args=--quiet&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform_docs&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/pre-commit/pre-commit-hooks&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v5.0.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;detect-aws-credentials&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pre-commit&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;detect&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AWS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;credentials"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;detect-private-key&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pre-commit&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;detect&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;private&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;keys"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;end-of-file-fixer&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pre-commit&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;fix&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trailing-whitespace&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pre-commit&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;remove&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;trailing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;whitespaces"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beyond quality and safety, presentation matters too! Just as chefs ensure consistent dish presentation, we also use &lt;code&gt;terraform fmt&lt;/code&gt; and others &lt;code&gt;pre-commit&lt;/code&gt; hooks to format our code in a consistent way. This makes our code easier to read, understand, and maintain, both for ourselves and our colleagues.&lt;/p&gt;

&lt;p&gt;Now that our kitchen is equipped, it's time to gather the ingredients for our infrastructure main dish: the Terraform root module. &lt;/p&gt;

&lt;h3&gt;
  
  
  8. Our Main Infrastructure Dish: The Terraform Root Module.
&lt;/h3&gt;

&lt;p&gt;Just like any good recipe, it requires the right ingredients, organized in the right way. HashiCorp suggests a &lt;a href="https://developer.hashicorp.com/terraform/language/modules/develop/structure" rel="noopener noreferrer"&gt;standard module structure&lt;/a&gt;, which we'll follow to ensure a well-structured and maintainable code. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root-module/
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── providers.tf
├── modules/
│   ├── child-module-A/
│   │   ├── README.md
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   ├── child-module-B/
│   ├── .../
├── .pre-commit-config.yaml
└── .tflint.hcl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our main dish structure defined, let's dive into a sample recipe specifically for AWS dishes.&lt;/p&gt;

&lt;h4&gt;
  
  
  A Sample Recipe for AWS
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;A template that serves as a foundation for creating Terraform modules.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/zidenis/terraform-module-template-aws" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is a handy module template to bootstrap your AWS resources. It serves as a foundation starting point for various AWS infrastructure creations, and includes essential ingredients for a robust and secure AWS setup, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An S3 Bucket for State Storage. It includes server-side encryption, versioning, and lifecycle rules for noncurrent object transition and expiration, ensuring the safety and management of our stored data. It also blocks public access, preventing unwanted access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A DynamoDB Table for State Locking. This acts as a coordination system in our kitchen, preventing conflicts when we have multiple chefs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Template usage example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure &lt;span class="c"&gt;# You will need the AWS CLI installed. Set up AWS credentials with privileges to provision resources. Remember to use temporary credentials or store permanent credentials outside the git repository.&lt;/span&gt;

git clone https://github.com/zidenis/terraform-module-template-aws.git my-terraform-module

&lt;span class="nb"&gt;cd &lt;/span&gt;my-terraform-module

git remote remove origin &lt;span class="c"&gt;# We remove the original remote to start our own module&lt;/span&gt;

&lt;span class="c"&gt;# Do not run this script if your intention is to develop the module locally.&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x backend_bootstrap.sh&lt;span class="p"&gt;;&lt;/span&gt; ./backend_bootstrap.sh &lt;span class="c"&gt;# optionally, use this bash script to set up the remote backend. &lt;/span&gt;

&lt;span class="nb"&gt;source&lt;/span&gt; ~/.venv/bin/activate

pre-commit &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--install-hooks&lt;/span&gt; &lt;span class="c"&gt;# set up your git repository to run pre-commit hooks automatically&lt;/span&gt;

pre-commit run &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="c"&gt;# optionally, run pre-commit hooks against all the files.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now start developing your specific module, using the provided structure and backend setup as a solid foundation. Using &lt;code&gt;pre-commit&lt;/code&gt;, you can run all the quality and security checks we set up earlier, ensuring a perfect and secure final dish.&lt;/p&gt;

&lt;h4&gt;
  
  
  pre-commit usage example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.venv/bin/activate

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# cooking a new module"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;  main.tf

git add main.tf

git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Cooking a new module"&lt;/span&gt;
&lt;span class="c"&gt;# [INFO] Initializing environment for https://github.com/antonbabenko/pre-commit-terraform.&lt;/span&gt;
&lt;span class="c"&gt;# [INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.&lt;/span&gt;
&lt;span class="c"&gt;# [INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.&lt;/span&gt;
&lt;span class="c"&gt;# [INFO] Once installed this environment will be reused.&lt;/span&gt;
&lt;span class="c"&gt;# [INFO] This may take a few minutes...&lt;/span&gt;
&lt;span class="c"&gt;# Terraform validate.......................................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Terraform fmt............................................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Terraform validate with tflint...........................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Terraform validate with trivy............................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Terraform validate with Checkov..........................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Terraform docs...........................................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Pre-commit detect AWS credentials........................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Pre-commit detect private keys...........................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Pre-commit fix end of files..............................................Passed&lt;/span&gt;
&lt;span class="c"&gt;# Pre-commit remove trailing whitespaces...................................Passed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By following this recipe, you've equipped your development environment with essential tools to write, validate, and secure Terraform modules effectively. This tutorial was designed to install the latest versions of the tools, but remember to regularly update your tools and configurations for optimal performance and compliance.&lt;/p&gt;

&lt;p&gt;Are there any additional tools or configurations you'd like to explore to complement the setup? are you using Generative AI to develop your terraform modules? please, tell me how. While Generative AI has the potential to streamline Terraform development by automating certain tasks like code generation or identifying potential issues. However, at this stage, I think it's likely not a core component for most users setting up a development environment. This is something that I plan to investigate.&lt;/p&gt;

&lt;p&gt;Let me know your thoughts and suggestions to improve this guide further. Happy coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools versions at the time of writing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tenv version
&lt;span class="c"&gt;# tenv version v3.2.11&lt;/span&gt;

terraform version
&lt;span class="c"&gt;# Terraform v1.10.3&lt;/span&gt;
&lt;span class="c"&gt;# on linux_amd64&lt;/span&gt;

terraform-docs version
&lt;span class="c"&gt;# terraform-docs version v0.19.0 af31cc6 linux/amd64&lt;/span&gt;

tflint &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# TFLint version 0.54.0&lt;/span&gt;
&lt;span class="c"&gt;# + ruleset.terraform (0.10.0-bundled)&lt;/span&gt;

trivy &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# Version: 0.58.0&lt;/span&gt;

checkov &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# 3.2.343&lt;/span&gt;

pre-commit &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;#pre-commit 4.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cleanup
&lt;/h2&gt;

&lt;p&gt;Clean up downloaded archives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TENV_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"tenv_v.*"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TDOC_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"terraform-docs-.+"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TFLINT_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"tflint_linux.+"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TRIVY_LATEST&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"trivy_.+"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;rm &lt;/span&gt;vscode.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>terraform</category>
      <category>infrastructureascode</category>
      <category>aws</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
