<?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>Forem: Rafael Herik de Carvalho</title>
    <description>The latest articles on Forem by Rafael Herik de Carvalho (@rafaelherik).</description>
    <link>https://forem.com/rafaelherik</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%2F1053084%2Ffc678c05-1ac7-49f5-924d-a40fb2562909.jpg</url>
      <title>Forem: Rafael Herik de Carvalho</title>
      <link>https://forem.com/rafaelherik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rafaelherik"/>
    <language>en</language>
    <item>
      <title>Bringing Azure Infrastructure into Kubernetes: Why ASO v2 is a Game Changer for GitOps</title>
      <dc:creator>Rafael Herik de Carvalho</dc:creator>
      <pubDate>Mon, 07 Apr 2025 16:54:21 +0000</pubDate>
      <link>https://forem.com/rafaelherik/bringing-azure-infrastructure-into-kubernetes-why-aso-v2-is-a-game-changer-for-gitops-4nmp</link>
      <guid>https://forem.com/rafaelherik/bringing-azure-infrastructure-into-kubernetes-why-aso-v2-is-a-game-changer-for-gitops-4nmp</guid>
      <description>&lt;p&gt;&lt;em&gt;Infrastructure as Code (IaC)&lt;/em&gt; isn’t just a best practice in modern cloud environments, it’s essential.&lt;/p&gt;

&lt;p&gt;As systems scale, teams need automation, consistency, and strong security to avoid the pitfalls of manual provisioning. IaC makes your infrastructure repeatable, auditable, and self-service-friendly — all while speeding up delivery.&lt;/p&gt;

&lt;p&gt;Traditionally, tools like &lt;em&gt;Terraform&lt;/em&gt;, &lt;em&gt;Bicep&lt;/em&gt;, and &lt;em&gt;ARM templates&lt;/em&gt; have been the standard for managing Azure infrastructure. But what if you could provision and manage your cloud resources the same way you manage your applications — using Kubernetes, CRDs, and GitOps workflows?&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;Azure Service Operator v2&lt;/strong&gt; (&lt;strong&gt;ASO v2&lt;/strong&gt;) comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ASO v2?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://azure.github.io/azure-service-operator/" rel="noopener noreferrer"&gt;Azure Service Operator v2&lt;/a&gt; is the official, production-grade Kubernetes operator built by &lt;strong&gt;Microsoft&lt;/strong&gt; for managing &lt;strong&gt;Azure&lt;/strong&gt; resources using Kubernetes-native APIs.&lt;/p&gt;

&lt;p&gt;It allows you to define and manage Azure services (e.g., &lt;em&gt;SQL Databases, Cosmos DB, Storage Accounts, Key Vaults&lt;/em&gt;) as Kubernetes Custom Resources — fully integrated with GitOps pipelines using tools like &lt;em&gt;Flux&lt;/em&gt; and &lt;em&gt;ArgoCD&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Compared to the original &lt;strong&gt;ASO&lt;/strong&gt;, version 2 brings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A modular, per-service architecture, so you can install only what you need&lt;/li&gt;
&lt;li&gt;Support for latest Azure API versions, mapped 1:1 to Azure's resource model&lt;/li&gt;
&lt;li&gt;Better multi-tenancy support and flexible identity management&lt;/li&gt;
&lt;li&gt;Improved controller reliability and reconciliation performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Matters in a GitOps World
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitOps&lt;/strong&gt; has changed the way we ship and manage applications — but applying &lt;em&gt;GitOps&lt;/em&gt; to infrastructure, especially stateful resources, is still challenging.&lt;/p&gt;

&lt;p&gt;Take a database, for example. Provisioning one isn’t just about spinning up a container. You also need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data persistence&lt;/li&gt;
&lt;li&gt;Backup and restore policies&lt;/li&gt;
&lt;li&gt;Geo-replication&lt;/li&gt;
&lt;li&gt;Access controls and secrets&lt;/li&gt;
&lt;li&gt;Performance configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most infrastructure tools treat this separately from the application layer. That can lead to siloed pipelines, manual work, and config drift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASO v2&lt;/strong&gt; brings infrastructure and app delivery together — in the same &lt;em&gt;GitOps&lt;/em&gt; flow. You define resources declaratively, store them in Git, and Kubernetes takes care of syncing the desired state with Azure.&lt;/p&gt;

&lt;h2&gt;
  
  
  How ASO v2 Works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ASO v2&lt;/strong&gt; works by introducing Azure-specific Custom Resource Definitions (CRDs) into your Kubernetes cluster. For each supported Azure service, there’s a matching Kubernetes resource type. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SqlServer and SqlDatabase for Azure SQL&lt;/li&gt;
&lt;li&gt;StorageAccount for Azure Blob/File/Table storage&lt;/li&gt;
&lt;li&gt;KeyVault, CosmosDB, PostgreSqlDatabase, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these resources is managed by a controller — a background process that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Watches for changes to the custom resources&lt;/li&gt;
&lt;li&gt;Validates desired state against current Azure state&lt;/li&gt;
&lt;li&gt;Makes API calls to Azure to bring the resource into alignment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means your Azure infrastructure becomes Kubernetes-native — you can kubectl apply a database, update it with a GitOps commit, and monitor it just like any other workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perfect for Hybrid Environments
&lt;/h2&gt;

&lt;p&gt;In real-world teams, hybrid environments are the norm: developers deploy applications, while platform teams manage infrastructure. ASO v2 helps bridge this gap by enabling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-service provisioning:&lt;/strong&gt; Developers can request their own databases or Key Vaults — with guardrails — using YAML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment consistency:&lt;/strong&gt; Staging, QA, and prod environments can be defined and reproduced identically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy enforcement:&lt;/strong&gt; Teams can apply RBAC, Azure AD identities, and resource quotas at the Kubernetes level.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can even use different credentials per namespace, meaning each team or workload can authenticate with different Azure identities — perfect for multi-tenant clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Provisioning an Azure SQL Database
&lt;/h2&gt;

&lt;p&gt;Here’s what an Azure SQL Database resource might look like using ASO v2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure.microsoft.com/v1api20211101&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SqlDatabase&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-database&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eastus&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-sql-server&lt;/span&gt;
  &lt;span class="na"&gt;collation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SQL_Latin1_General_CP1_CI_AS&lt;/span&gt;
  &lt;span class="na"&gt;maxSizeBytes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5368709120&lt;/span&gt;  &lt;span class="c1"&gt;# 5 GB&lt;/span&gt;
  &lt;span class="na"&gt;sku&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S1&lt;/span&gt;
    &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Standard&lt;/span&gt;
    &lt;span class="na"&gt;capacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lives alongside your app code and gets deployed via GitOps. Need to change the SKU or scale up storage? Just edit the file and commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ASO Can’t (Yet) Do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ASO v2&lt;/strong&gt; is powerful, but it’s important to note a few things it doesn’t do — at least not yet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can’t create a database from a backup directly in the &lt;strong&gt;CRD&lt;/strong&gt; (&lt;em&gt;like point-in-time restore or copy from another DB&lt;/em&gt;). This still needs to be done using &lt;strong&gt;CLI&lt;/strong&gt; or &lt;strong&gt;ARM&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Not all Azure services are supported yet (but the list is growing fast).&lt;/li&gt;
&lt;li&gt;It’s not a full replacement for &lt;strong&gt;Terraform&lt;/strong&gt;/&lt;strong&gt;Bicep&lt;/strong&gt; — rather, it's a GitOps-friendly complement that excels in app-adjacent infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Benefits for Teams
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitOps-native Azure infrastructure&lt;/li&gt;
&lt;li&gt;Modular installation — only install the Azure services you need&lt;/li&gt;
&lt;li&gt;Fine-grained identity control using Azure AD Workload Identity&lt;/li&gt;
&lt;li&gt;Unified workflows for app + infra using Kubernetes-native tooling&lt;/li&gt;
&lt;li&gt;Developer enablement with self-service infra provisioning&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ASO v2 and Crossplane: Competing or Complementary?
&lt;/h2&gt;

&lt;p&gt;As more teams adopt GitOps and Kubernetes-native infrastructure workflows, it's natural to compare tools like &lt;strong&gt;ASO v2&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://crossplane.io" rel="noopener noreferrer"&gt;Crossplane&lt;/a&gt;&lt;/strong&gt; — both aim to bring cloud resource management into the Kubernetes world.&lt;/p&gt;

&lt;p&gt;While they share similar goals and some overlapping features, this post is focused on ASO v2. I won’t dive into a full comparison here — but stay tuned! I’ll be sharing a dedicated post soon that explores Crossplane in more depth, along with a detailed side-by-side breakdown.&lt;/p&gt;

&lt;p&gt;For now, just know that these tools aren’t necessarily competing — they can be complementary, depending on your cloud strategy and team structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;GitOps&lt;/em&gt; and &lt;em&gt;Kubernetes&lt;/em&gt; have changed how we manage modern applications. With &lt;em&gt;Azure Service Operator v2&lt;/em&gt;, you can bring those same practices to your infrastructure — making Azure resources part of your Kubernetes-native, declarative workflows.&lt;/p&gt;

&lt;p&gt;Whether it’s provisioning databases, Key Vaults, or storage accounts, ASO v2 helps you build secure, consistent, and repeatable environments — all from YAML.&lt;/p&gt;

&lt;p&gt;That said, tools like Terraform and Bicep aren’t going away. A hybrid approach is a good option:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform teams&lt;/strong&gt; use Terraform/Bicep to set up baseline infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developers&lt;/strong&gt; use ASO v2 / Crossplane to provision and manage app-specific resources, backed by GitOps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, you get the stability of traditional IaC and the flexibility of Kubernetes-native workflows.&lt;/p&gt;

&lt;p&gt;Microsoft is continuing to invest in ASO, and it’s already proving to be a powerful tool for hybrid and cloud-native teams alike.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>kubernetes</category>
      <category>git</category>
      <category>devops</category>
    </item>
    <item>
      <title>Kubernetes Operators - The k8s orchestration "service"</title>
      <dc:creator>Rafael Herik de Carvalho</dc:creator>
      <pubDate>Mon, 07 Apr 2025 15:28:10 +0000</pubDate>
      <link>https://forem.com/rafaelherik/kubernetes-operators-the-k8s-orchestration-service-3ic5</link>
      <guid>https://forem.com/rafaelherik/kubernetes-operators-the-k8s-orchestration-service-3ic5</guid>
      <description>&lt;p&gt;If you're familiar with Kubernetes, you've probably heard of, used, or at least come across the term "Operators." In simple terms, an Operator is a software extension to Kubernetes that helps manage applications and their components by automating complex tasks.&lt;/p&gt;

&lt;p&gt;The official Kubernetes definition is:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Operators are software extensions to Kubernetes that make use of custom resources to manage applications and their components. Operators follow Kubernetes principles, notably the control loop".&lt;/em&gt; &lt;a href="//kubernetes.io/docs/concepts/extend-kubernetes/operator/"&gt;kubernetes.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5rfkak0vjp6qhn62qyv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5rfkak0vjp6qhn62qyv.png" alt="by Cloud Native Foundation P" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Exactly Are Kubernetes Operators?
&lt;/h2&gt;

&lt;p&gt;Think of Operators as specialized tools designed to simplify the management of your software. Instead of manually handling every individual part of an application—like servers, storage, or networking—an Operator allows us to treat the entire application as one cohesive unit. This way, we can focus only on the parts that need adjusting, without worrying about the technical details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automation Made Easy
&lt;/h2&gt;

&lt;p&gt;Operators are not only powerful in managing applications, but they also automate everyday tasks. For instance, they handle installation, configuration, updates, backups, and even recovery—all without requiring manual intervention. Because Operators are built into the Kubernetes system, they integrate smoothly with it, allowing everything to work seamlessly together.&lt;br&gt;
How Do Kubernetes Operators Work?&lt;/p&gt;

&lt;p&gt;At a high level, Operators function as controllers that make it easier to package, deploy, and manage software on Kubernetes. They use Custom Resource Definitions (CRDs) to specify how an application should behave. These definitions allow the Operator to continuously monitor and adjust the application, ensuring that it always matches the desired state.&lt;/p&gt;

&lt;p&gt;For example, if an application needs more resources or a restart, the Operator can take care of it automatically, skipping any human intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are Operators So Powerful?
&lt;/h2&gt;

&lt;p&gt;In essence, Operators take on the heavy lifting of managing complex applications. By using Kubernetes APIs and principles, Operators can automate tasks that would otherwise require manual configuration or intervention. This makes them an invaluable tool for any Kubernetes-based infrastructure, offering streamlined management and reducing the need for constant oversight.&lt;/p&gt;

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

&lt;p&gt;Kubernetes Operators are "set-it-and-forget-it" tools that automate and manage complex tasks behind the scenes, ensuring your applications stay healthy, up to date, and running smoothly. They bring immense power, particularly in complex or large-scale environments, by eliminating manual intervention and streamlining processes. With Operators, you can save time, optimize resources, and maintain consistency and reliability across your Kubernetes cluster, making them an essential tool for modern application management.&lt;/p&gt;

&lt;h2&gt;
  
  
  References:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cncf.io/blog/2022/06/15/kubernetes-operators-what-are-they-some-examples/" rel="noopener noreferrer"&gt;https://www.cncf.io/blog/2022/06/15/kubernetes-operators-what-are-they-some-examples/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Azure Verified Modules: Consolidated Standards for a Good IaC</title>
      <dc:creator>Rafael Herik de Carvalho</dc:creator>
      <pubDate>Wed, 04 Sep 2024 07:30:42 +0000</pubDate>
      <link>https://forem.com/rafaelherik/azure-verified-modules-consolidated-standards-for-a-good-iac-oh4</link>
      <guid>https://forem.com/rafaelherik/azure-verified-modules-consolidated-standards-for-a-good-iac-oh4</guid>
      <description>&lt;p&gt;Microsoft introduced the AVM(Azure Verified Modules) as part of an effort to help internal and external parties build well-designed and reliable infrastructure using infrastructure as code.&lt;/p&gt;

&lt;p&gt;"Azure Verified Modules enable and accelerate consistent solution development and delivery of cloud-native or migrated applications and their supporting infrastructure by codifying Microsoft guidance (&lt;a href="https://learn.microsoft.com/en-us/azure/well-architected/" rel="noopener noreferrer"&gt;WAF - Well-Architected Framework&lt;/a&gt;), with best practice configurations." - &lt;a href="https://azure.github.io/Azure-Verified-Modules/" rel="noopener noreferrer"&gt;Azure Verified Modules&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With AVM, Microsoft aims to provide a single definition of a suitable IaC module. This initiative is not about Bicep but multiple IaC languages, following the principles of the well-architected framework.&lt;/p&gt;

&lt;p&gt;These clearly defined statements will help organizations drive &lt;em&gt;Cloud Adoption&lt;/em&gt; and mature their cloud infrastructure according to best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AVM?
&lt;/h2&gt;

&lt;p&gt;The community has been throwing a bunch of Infrastructure as Code (IaC) modules at the wall, but nothing's really stuck as the go-to, trustworthy source. We've got modules in different languages, styles, and support levels scattered all over the place. &lt;/p&gt;

&lt;p&gt;This new effort is about creating a unified strategy for IaC modules that customers and partners can rely on. The goal is to build a consistent, supported, and available library of modules in whatever language you prefer. &lt;/p&gt;

&lt;p&gt;This should help speed up projects like Landing Zone Accelerators and give users solid building blocks, no matter where they are in their IaC journey. Plus, it addresses the big headache of support - customers need to know Microsoft's got their back when using these modules, especially in enterprise settings. &lt;/p&gt;

&lt;p&gt;Basically, they're trying to clean up the chaos and give people something they can trust and build on without worrying about it falling apart when it matters most.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proposed design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd746rnxxjiy10owwo4c7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd746rnxxjiy10owwo4c7.png" alt="Architecture of AVM" width="703" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the image above you can see the AVM design, it's supported by &lt;strong&gt;Azure Resource Manager&lt;/strong&gt;, then all &lt;strong&gt;Domain Specific Languages&lt;/strong&gt; such &lt;em&gt;Bicep&lt;/em&gt; and &lt;em&gt;Terraform&lt;/em&gt; implements the resource management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AVM&lt;/strong&gt; provides three types of Modules: &lt;strong&gt;Resource Modules&lt;/strong&gt;, &lt;strong&gt;Patern Modules&lt;/strong&gt; and &lt;strong&gt;Utility Modules&lt;/strong&gt;. See more about Modules Classification &lt;a href="https://azure.github.io/Azure-Verified-Modules/specs/shared/module-classifications/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Resource Modules
&lt;/h3&gt;

&lt;p&gt;Resource modules are designed to manage specific Azure Resources like &lt;em&gt;Virtual Machines&lt;/em&gt;, &lt;em&gt;Virtual Networks&lt;/em&gt;, &lt;em&gt;and Azure Kubernetes Services(AKS)&lt;/em&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern Modules
&lt;/h3&gt;

&lt;p&gt;Pattern modules are designed to implement specific architectural patterns, often involving multiple resources working together. A prime example is a production-ready Azure Kubernetes Service (AKS) deployment. Setting up AKS properly involves more than just provisioning the AKS resource itself - it requires configuring network-related resources, setting up a private container registry for enhanced security, and applying various other specific configurations. Pattern modules simplify this process by encapsulating all these components and best practices into a single, easy-to-use module. This approach significantly reduces complexity and helps users deploy comprehensive, well-architected solutions with less effort and reduced risk of misconfiguration. See this module example for &lt;a href="https://registry.terraform.io/modules/Azure/avm-ptn-aks-production/azurerm/latest" rel="noopener noreferrer"&gt;AKS production ready Terraform module&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Utility Modules
&lt;/h3&gt;

&lt;p&gt;Utility modules implement functions and routines that can be used by Resouce and Pattern modules, but they MUST NOT deploy any Azure Resource; they are only utilities.&lt;/p&gt;

&lt;p&gt;If you use IaC to provision Azure infrastructure, the &lt;a href="https://azure.github.io/Azure-Verified-Modules/" rel="noopener noreferrer"&gt;AVM Overview&lt;/a&gt; must be read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available Modules
&lt;/h2&gt;

&lt;p&gt;For now (Sep 2024), only Bicep and Terraform are supported, AVM uses Bicep Registry and Terraform Registry to share the modules:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Module Type&lt;/th&gt;
&lt;th&gt;Published&lt;/th&gt;
&lt;th&gt;Proposed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bicep&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Resource&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;135&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Pattern&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Utility&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Terraform&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Resource&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;td&gt;86&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Pattern&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Utility&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note: Data as of September 2024&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributing
&lt;/h3&gt;

&lt;p&gt;If you want to contribute, you can even propose a new module or develop or contribute to an existing module:&lt;/p&gt;

&lt;h4&gt;
  
  
  Bicep
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/Azure-Verified-Modules/issues?q=is%3Aopen+is%3Aissue+label%3A" rel="noopener noreferrer"&gt;Modules looking for Contributors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/Azure-Verified-Modules/issues?q=is%3Aopen+is%3Aissue+label%3A" rel="noopener noreferrer"&gt;Orphaned modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/Azure-Verified-Modules/issues?q=is%3Aissue+label%3A" rel="noopener noreferrer"&gt;Modules looking for Owners&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Terraform
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/Azure-Verified-Modules/issues?q=is%3Aissue+label%3A" rel="noopener noreferrer"&gt;Modules looking for Contributors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/Azure-Verified-Modules/issues?q=is%3Aopen+is%3Aissue+label%3A" rel="noopener noreferrer"&gt;Orphaned modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/Azure-Verified-Modules/issues?q=is%3Aissue+is%3Aopen+label%3A" rel="noopener noreferrer"&gt;Modules looking for Owners&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Update: I've missed adding the observation that only Microsoft full-time employees can be module owners for now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;For large cloud environments, the AVM still needs to deliver its full potential; it needs some maturing and the implementation of new modules. However, as it is a good standard, you can get started with the modules already available and contribute to the initiative.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://azure.github.io/Azure-Verified-Modules/" rel="noopener noreferrer"&gt;Azure Verified Modules&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=JbIMrJKW5N0" rel="noopener noreferrer"&gt;An Introduction to Azure Verified Modules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>terraform</category>
      <category>bicep</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>In Light of Terraform Licensing Changes, OpenTofu Offers a Free, Open-Source Path</title>
      <dc:creator>Rafael Herik de Carvalho</dc:creator>
      <pubDate>Tue, 03 Sep 2024 09:12:03 +0000</pubDate>
      <link>https://forem.com/rafaelherik/in-light-of-terraform-licensing-changes-opentofu-offers-a-free-open-source-path-26dc</link>
      <guid>https://forem.com/rafaelherik/in-light-of-terraform-licensing-changes-opentofu-offers-a-free-open-source-path-26dc</guid>
      <description>&lt;p&gt;As of April 2024, &lt;strong&gt;HashiCorp&lt;/strong&gt; has become part of &lt;strong&gt;IBM&lt;/strong&gt;. This acquisition has sparked concerns about the future of &lt;strong&gt;Terraform&lt;/strong&gt;, mainly due to HashiCorp’s controversial license change to a BSL License in August 2023.&lt;/p&gt;

&lt;p&gt;"BSL 1.1 is a source-available license that allows copying, modification, redistribution, non-commercial use, and commercial use under specific conditions."&lt;/p&gt;

&lt;p&gt;This scenario exemplifies the challenge of monetising open-source software. Large open-source projects are typically sustained by big tech companies, which provide funding and engineering resources. This support allows projects to maintain a dedicated workforce to keep the development engine running smoothly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concerns Surrounding the Acquisition
&lt;/h2&gt;

&lt;p&gt;Two main concerns have been raised about IBM’s acquisition of &lt;strong&gt;HashiCorp&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;IBM's Track Record: &lt;strong&gt;IBM&lt;/strong&gt; has a history of unsuccessful acquisitions of promising companies, which raises doubts about the future success of &lt;strong&gt;Terraform&lt;/strong&gt; under its new ownership.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conflict of Interest: IBM’s cloud offerings present a potential conflict of interest. Terraform is widely used to manage infrastructure on major cloud platforms like AWS, Azure, and GCP. This could reduce effort or interest in maintaining integrations with competing cloud providers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Considering Alternatives to Terraform
&lt;/h2&gt;

&lt;p&gt;If you are currently using Terraform and are not inclined to acquire licenses in the future, consider exploring alternatives. The most straightforward option is &lt;a href="https://opentofu.org" rel="noopener noreferrer"&gt;OpenTofu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Following the license change, a private fork of Terraform was created, leading to the release of &lt;strong&gt;OpenTofu&lt;/strong&gt;. You can read the official announcement here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform vs OpenTofu: What Are the Differences?
&lt;/h2&gt;

&lt;p&gt;Apart from licensing, Terraform and OpenTofu are fundamentally the same. Since the fork is relatively recent, they function very similarly. Here's an overview:&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing OpenTofu
&lt;/h2&gt;

&lt;p&gt;For Linux and macOS, you can install &lt;strong&gt;OpenTofu&lt;/strong&gt; via &lt;strong&gt;Homebrew&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
brew update
brew &lt;span class="nb"&gt;install &lt;/span&gt;opentofu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage&lt;br&gt;
After installation, using OpenTofu is almost identical to using Terraform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;azurerm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"hashicorp/azurerm"&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;"4.1.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"azurerm"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;features&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"example-rg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"example-rg"&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"West Europe"&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this infrastructure configured, initialize OpenTofu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
tofu init

Initializing the backend...

Initializing provider plugins...

OpenTofu has been successfully initialized!

You may now begin working with OpenTofu. Try running &lt;span class="s2"&gt;"tofu plan"&lt;/span&gt; to see any changes that are required &lt;span class="k"&gt;for &lt;/span&gt;your infrastructure. All OpenTofu commands should now work.

If you ever &lt;span class="nb"&gt;set &lt;/span&gt;or change modules or backend configuration &lt;span class="k"&gt;for &lt;/span&gt;OpenTofu, rerun this &lt;span class="nb"&gt;command &lt;/span&gt;to reinitialize your working directory. If you forget, other commands will detect it and remind you to &lt;span class="k"&gt;do &lt;/span&gt;so &lt;span class="k"&gt;if &lt;/span&gt;necessary.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From now on, you only need to replace the &lt;code&gt;terraform&lt;/code&gt; command with &lt;code&gt;tofu&lt;/code&gt; to run your IaC.&lt;/p&gt;

&lt;p&gt;For more details on migrating from Terraform to OpenTofu, visit the &lt;a href="https://opentofu.org/docs/intro/migration/" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I'm launching a new GitHub repo to explore examples using OpenTofu further. Please follow the repo &lt;a href="https://github.com/rafaelherik/opentofu-demo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post aims to introduce OpenTofu as a viable alternative and encourage community engagement in using and improving this important tool in the modern cloud development landscape.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Case for Terraform Modules: Why Not Just Use Providers Directly?</title>
      <dc:creator>Rafael Herik de Carvalho</dc:creator>
      <pubDate>Tue, 20 Aug 2024 08:58:54 +0000</pubDate>
      <link>https://forem.com/rafaelherik/the-case-for-terraform-modules-why-not-just-use-providers-directly-h07</link>
      <guid>https://forem.com/rafaelherik/the-case-for-terraform-modules-why-not-just-use-providers-directly-h07</guid>
      <description>&lt;p&gt;When it comes to large-scale Infrastructure as Code (IaC) for complex cloud environments, managing the sheer number of resources is not the only challenge. The real differentiator lies in provisioning infrastructure according to strict governance, security, and availability requirements without introducing unnecessary complexity or increasing the risk of human error during the design and implementation process.&lt;/p&gt;

&lt;p&gt;In large-scale environments, we encounter a set of pre-established definitions that encompass everything from corporate standards to security practices and cost management. These guidelines, though essential, often make the process of writing infrastructure code more challenging, demanding speed, efficiency, and compliance.&lt;/p&gt;

&lt;p&gt;Developing modules in Terraform is a key strategy to manage this complexity. Modules not only help create consistent patterns but also enable engineers to describe and provision the required infrastructure without worrying about all the compliance and security details. Rather than limiting creativity and agility, modules provide a solid foundation that ensures best practices are followed.&lt;/p&gt;

&lt;p&gt;Security awareness is crucial in cloud development, but it should not be an obstacle. On the contrary, it should be a core part of the organizational culture, naturally integrated into the design and implementation process of cloud solutions.&lt;/p&gt;

&lt;p&gt;To address the main question, let's start with the basics: What is Terraform?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Terraform is an infrastructure as code tool developed by HashiCorp that allows you to define both cloud and on-premises resources in human-readable configuration files that can be versioned, reused, and shared. You can then use a consistent workflow to provision and manage your entire infrastructure throughout its lifecycle. Terraform can manage low-level components like compute, storage, and networking resources, as well as high-level components like DNS entries and SaaS features." — HashiCorp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What is a provider in Terraform?
&lt;/h3&gt;

&lt;p&gt;A provider in Terraform is a plugin that allows Terraform to interact with various platforms, services, or APIs. Providers are a crucial component in Terraform's architecture, enabling the tool to manage and configure resources across different systems.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Points about Terraform Providers:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform Interaction&lt;/strong&gt;: Providers are responsible for translating Terraform's declarative code into API calls that integrate with an infrastructure platform. This platform can be a cloud provider like Azure or AWS, a Software as a Service (SaaS) like GitHub or Datadog, or even on-premises systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Management&lt;/strong&gt;: Each provider defines a set of resources it can manage. These resources are declared in Terraform configuration files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Management&lt;/strong&gt;: Providers work with Terraform to manage the state of the infrastructure, allowing Terraform to understand what changes are necessary during a &lt;code&gt;terraform apply&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Installation and Versioning&lt;/strong&gt;: Providers are distributed as plugins, and Terraform automatically downloads the required providers when you initialize your configuration (&lt;code&gt;terraform init&lt;/code&gt;). Each provider has its own versioning, and you can specify the version you need in your configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt;: If a platform or service doesn't have an official provider, you can develop a custom provider using the Terraform SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example:
&lt;/h4&gt;

&lt;p&gt;If you want to manage resources in AWS using Terraform, you need to use the AWS provider. In your configuration file, you would declare your provider like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&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;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-123456"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;aws&lt;/code&gt; provider allows Terraform to integrate with AWS.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aws_instance&lt;/code&gt; resource is defined by the AWS provider and represents an EC2 instance in AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Providers are essential to Terraform's operation because they abstract the complexity of interacting with different platforms, making infrastructure as code easily manageable across multiple environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a module in Terraform?
&lt;/h3&gt;

&lt;p&gt;A module in Terraform is a container for one or more resources that are used together. It is a fundamental unit of code organization in Terraform, serving to group related resources and make configurations more modular, reusable, and easier to manage.&lt;/p&gt;

&lt;p&gt;Essentially, a Terraform module is a set of &lt;code&gt;.tf&lt;/code&gt; files in a directory. Every configuration file (&lt;code&gt;.tf&lt;/code&gt;) in a directory is implicitly considered part of the module. When you start a project and create the &lt;code&gt;main.tf&lt;/code&gt;, &lt;code&gt;output.tf&lt;/code&gt;, and &lt;code&gt;variables.tf&lt;/code&gt; files, this set of files in the root directory is called the "root module."&lt;/p&gt;

&lt;p&gt;You can explicitly use modules by placing related configurations in a directory and calling the module from your configuration file (&lt;code&gt;.tf&lt;/code&gt;) in the root module or any other module.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reusability:
&lt;/h4&gt;

&lt;p&gt;Modules allow you to encapsulate patterns in your resource declarations and reuse them in multiple projects or environments. This reduces code duplication and makes your configuration more DRY (Don't Repeat Yourself).&lt;/p&gt;

&lt;p&gt;For example, you can create a module to handle common tasks like provisioning an EC2 instance, configuring a network, or provisioning a Kubernetes cluster. Once the module is created, it can be used in different configurations by simply referencing it.&lt;/p&gt;

&lt;p&gt;Modules typically accept &lt;strong&gt;inputs&lt;/strong&gt; (variables) and produce &lt;strong&gt;outputs&lt;/strong&gt;. This allows you to customize the module's behavior based on your needs and pass information from one module to other parts of your Terraform configuration.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to use a module?
&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;module&lt;/span&gt; &lt;span class="s2"&gt;"ec2_instance"&lt;/span&gt; &lt;span class="p"&gt;{&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;"./modules/ec2-instance"&lt;/span&gt; 
    &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt; 
    &lt;span class="nx"&gt;ami_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-123456"&lt;/span&gt; 
    &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vpc-123456"&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;ec2_instance&lt;/code&gt; module is referenced from a directory called &lt;code&gt;./modules/ec2-instance&lt;/code&gt;. Variables like &lt;code&gt;instance_type&lt;/code&gt;, &lt;code&gt;ami_id&lt;/code&gt;, and &lt;code&gt;vpc_id&lt;/code&gt; are passed to the module.&lt;/p&gt;

&lt;p&gt;Modules can be referenced from various sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Locally&lt;/strong&gt;: &lt;code&gt;source = "./modules/my-module"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform Registry&lt;/strong&gt;: &lt;code&gt;source = "terraform-aws-modules/vpc/aws"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git Repositories&lt;/strong&gt;: &lt;code&gt;source = "git::https://github.com/user/repo.git//path/to/module"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Terraform Module Registry
&lt;/h3&gt;

&lt;p&gt;The Terraform Module Registry is a public repository where you can find and share modules created by the community. It offers various commonly used modules that can save significant development time when provisioning infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the advantages of using Terraform modules?
&lt;/h3&gt;

&lt;p&gt;There are several advantages to using Terraform modules. The ability to reuse code and standardize it are key factors driving teams to adopt Terraform modules.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example without a module:
&lt;/h4&gt;

&lt;p&gt;Here’s what the code to create a virtual machine in Azure would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.tf&lt;/span&gt;

&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;azurerm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"hashicorp/azurerm"&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;"3.116.0"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"azurerm"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;features&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"rg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"myresourcegroup"&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"West Europe"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_virtual_network"&lt;/span&gt; &lt;span class="s2"&gt;"vnet"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"myvnet"&lt;/span&gt;
    &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
    &lt;span class="nx"&gt;address_space&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.0.0.0/16"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"subnet"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mysubnet"&lt;/span&gt;
    &lt;span class="nx"&gt;resource_group_name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;virtual_network_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_virtual_network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;address_prefixes&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.1.0.0/24"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_network_interface"&lt;/span&gt; &lt;span class="s2"&gt;"nic"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"myvmnic"&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
    &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;ip_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;                          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"myvmnicconfig"&lt;/span&gt;
        &lt;span class="nx"&gt;private_ip_address_allocation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Dynamic"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_virtual_machine"&lt;/span&gt; &lt;span class="s2"&gt;"vm"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"myvm"&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
    &lt;span class="nx"&gt;resource_group_name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;network_interface_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;azurerm_network_interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;vm_size&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Standard_DS1_v2"&lt;/span&gt;

    &lt;span class="nx"&gt;os_profile_linux_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;disable_password_authentication&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;os_profile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;computer_name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hostname"&lt;/span&gt;
        &lt;span class="nx"&gt;admin_username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"testadmin"&lt;/span&gt;
        &lt;span class="nx"&gt;admin_password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Password1234!"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;storage_image_reference&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;publisher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Canonical"&lt;/span&gt;
        &lt;span class="nx"&gt;offer&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0001-com-ubuntu-server-jammy"&lt;/span&gt;
        &lt;span class="nx"&gt;sku&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"22_04-lts"&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;"latest"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;storage_os_disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"myosdisk"&lt;/span&gt;
        &lt;span class="nx"&gt;caching&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ReadWrite"&lt;/span&gt;
        &lt;span class="nx"&gt;create_option&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"FromImage"&lt;/span&gt;
        &lt;span class="nx"&gt;managed_disk_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Standard_LRS"&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;p&gt;In this example, to create a virtual machine, you also need to create a virtual network, a subnet, a network interface, and a resource group. This adds some complexity due to the need to manage resources related to the virtual machine, which could be managed separately.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example with the use of a module:
&lt;/h4&gt;

&lt;p&gt;Now see how using a module can simplify the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.tf&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"azurerm"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;features&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"example-resources"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"East US"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"network"&lt;/span&gt; &lt;span class="p"&gt;{&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;"./network/vnet"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;vnets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;vnet1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vnet1"&lt;/span&gt;
      &lt;span class="nx"&gt;address_space&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.0.0.0/16"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;subnets&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


        &lt;span class="nx"&gt;subnet1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"subnet1"&lt;/span&gt;
          &lt;span class="nx"&gt;address_prefixes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.0.1.0/24"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"nic"&lt;/span&gt; &lt;span class="p"&gt;{&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;"./network/nic"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;nics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nicvm1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nicvm1"&lt;/span&gt;
      &lt;span class="nx"&gt;subnet_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vnet_ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vnet1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"subnet1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"compute"&lt;/span&gt; &lt;span class="p"&gt;{&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;"./compute/vm"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;vms&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;vm1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vm1"&lt;/span&gt;
      &lt;span class="nx"&gt;size&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Standard_B1s"&lt;/span&gt;
      &lt;span class="nx"&gt;admin_username&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"adminuser"&lt;/span&gt;
      &lt;span class="nx"&gt;admin_password&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"P@ssw0rd1234!"&lt;/span&gt;
      &lt;span class="nx"&gt;nic_name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nicvm1"&lt;/span&gt;
      &lt;span class="nx"&gt;image_publisher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Canonical"&lt;/span&gt;
      &lt;span class="nx"&gt;image_offer&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"UbuntuServer"&lt;/span&gt;
      &lt;span class="nx"&gt;image_sku&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"18.04-LTS"&lt;/span&gt;
      &lt;span class="nx"&gt;image_version&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"latest"&lt;/span&gt;
    &lt;span class="p"&gt;}&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;p&gt;In this example, three modules were used, reducing the complexity of creating one or more virtual machines. &lt;/p&gt;

&lt;p&gt;Another important factor is abstraction and encapsulation. By developing a module, you can simplify resource management and design infrastructure that is more user-friendly for those who will consume these modules. &lt;/p&gt;

&lt;p&gt;Imagine that your company decides that only Ubuntu version 22.04 will be available for creating virtual machines. You can set this as a default value in the module and omit it from the configuration. Another important aspect is security: for example, you could enforce that Linux virtual machines are only created with SSH key authentication, disabling password authentication. &lt;/p&gt;

&lt;p&gt;From a governance perspective, you can establish naming standards and tags that are transparent to the user but ensure your infrastructure remains compliant.&lt;/p&gt;

&lt;p&gt;Modules are a great strategy, but using providers directly can be advantageous when the complexity is low and the number of resources doesn't justify the use of modules.&lt;/p&gt;

&lt;p&gt;Modules make your infrastructure as code more secure, reusable, and reliable. They shouldn't be seen as a complicating factor; whenever you choose to use modules, ensure they are up to date with provider versions, test your modules, and ensure they are an aid to those who use them, not a burden.&lt;/p&gt;

&lt;p&gt;See more on: &lt;a href="https://github.com/rafaelherik/terraform-samples" rel="noopener noreferrer"&gt;https://github.com/rafaelherik/terraform-samples&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>cloud</category>
      <category>cloudcomputing</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>Improving Cloud governance using an automated naming generation tool.</title>
      <dc:creator>Rafael Herik de Carvalho</dc:creator>
      <pubDate>Wed, 14 Aug 2024 14:13:04 +0000</pubDate>
      <link>https://forem.com/rafaelherik/improving-cloud-governance-using-an-automated-naming-generation-tool-5eoc</link>
      <guid>https://forem.com/rafaelherik/improving-cloud-governance-using-an-automated-naming-generation-tool-5eoc</guid>
      <description>&lt;p&gt;Managing cloud assets efficiently is crucial for governance, operational management, and accounting. One of the key challenges is ensuring consistent and meaningful naming of resources, which becomes increasingly complex as your infrastructure grows. Without a standardized naming convention, locating and managing resources can be time-consuming and error-prone, leading to inefficiencies and increased costs.&lt;/p&gt;

&lt;p&gt;This article introduces an automated approach to generating resource names using a Terraform provider. This solution simplifies the naming process, ensuring consistency and compliance across your cloud environment. Implementing this automated naming convention lets you quickly locate and manage resources, improve governance, and streamline operational workflows.&lt;/p&gt;

&lt;p&gt;Additionally, this approach helps associate cloud usage costs with business teams through chargeback and showback mechanisms. With well-defined naming and metadata tagging conventions, you can more accurately track and allocate expenses, making it easier to manage budgets and optimize resource utilization.&lt;/p&gt;

&lt;p&gt;Implementing an automated resource naming solution with Terraform not only saves time and reduces human error but also enhances your overall cloud management strategy, providing clear benefits in governance, operational efficiency, and cost control.&lt;/p&gt;

&lt;h2&gt;
  
  
  AzureNamingTool
&lt;/h2&gt;

&lt;p&gt;AzureNamingTool was created to help administrators define and manage their naming conventions while providing users with a simple interface for generating compliant names. The tool was developed using a naming pattern based on Microsoft's best practices.&lt;/p&gt;

&lt;p&gt;This tool is extensible, and you can apply new components to the name generation and improve the policies used to generate names.&lt;/p&gt;

&lt;p&gt;It's an open-source tool, and you can extend it to fit your needs, add extra functionalities, and customize its content. This flexibility puts you in control, and your heart makes the tool adaptable to your unique requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use a Terraform Provider?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Benefits of a Declarative API
&lt;/h3&gt;

&lt;p&gt;Terraform's declarative API offers significant advantages for managing resource naming conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Simplicity and Clarity: By defining the desired state of resource names, you can ensure consistency and avoid naming conflicts. Terraform configurations are straightforward, making it easy to understand and manage the naming conventions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automation: A declarative approach allows for the automation of resource naming, reducing the need for manual intervention and minimizing human error. This automation ensures that all resources follow the defined naming standards automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability: As your infrastructure grows, maintaining a consistent naming convention manually becomes increasingly challenging. Terraform's declarative model scales seamlessly, enabling you to manage large and complex environments with ease.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  State Management for Naming Convention
&lt;/h3&gt;

&lt;p&gt;Terraform's state management is a powerful feature that tracks the current state of your infrastructure. This capability is particularly beneficial for enforcing naming conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Consistency: Terraform maintains a state file that records the names of all resources, ensuring that changes are applied consistently across your environment. This prevents discrepancies and maintains uniformity in resource naming.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Version Control: State management allows for versioning, making it possible to track changes to naming conventions over time. This historical insight helps in auditing and compliance, providing a clear record of how resource names have evolved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conflict Resolution: Terraform's state management helps in detecting and resolving naming conflicts before they occur. By keeping track of the existing resource names, Terraform can prevent duplicate names and ensure that new resources adhere to the naming standards.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup the environment
&lt;/h2&gt;

&lt;p&gt;To make the Azure Naming Tool work, you must deploy and configure it. Then, you can start using the &lt;strong&gt;Terraform provider&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You must consider the &lt;strong&gt;compatibility matrix&lt;/strong&gt; related to which provider version you can use to communicate with your &lt;strong&gt;Azure Naming Tool&lt;/strong&gt; Api.&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure Naming Tool
&lt;/h3&gt;

&lt;p&gt;AzureNamingTool offers multiple installations modes, the easiest one is running it in a Container, but you can also deploy it to an App Service: &lt;a href="https://github.com/mspnp/AzureNamingTool/wiki#installation" rel="noopener noreferrer"&gt;More details here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use the Terraform provider, you must choose the best installation mode and generate the &lt;strong&gt;&lt;em&gt;APIKEY&lt;/em&gt;&lt;/strong&gt; that the provider will use to generate names.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Terraform provider
&lt;/h3&gt;

&lt;p&gt;I've created a new provider to provide the interface to request names to AzureNamingTool.&lt;/p&gt;

&lt;p&gt;The provider's v1.0.0 is quite simple. It cannot manage all the entities, only the resource names.&lt;/p&gt;

&lt;p&gt;To see more: &lt;a href="https://registry.terraform.io/providers/rafaelherik/aznamingtool/latest/docs" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to configure the provider
&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;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;aznamingtool&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"registry.terrafrom.io/rafaelherik/aznamingtool"&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;"1.0.0-beta"&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aznamingtool"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;api_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_API_KEY"&lt;/span&gt;
  &lt;span class="nx"&gt;base_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://AZURE_NAMING_TOOL_BASE_URL"&lt;/span&gt;
  &lt;span class="nx"&gt;admin_password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_ADMIN_PASSWORD"&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How to create a new Azure Resource using a name provided by the naming tool
&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;variable&lt;/span&gt; &lt;span class="s2"&gt;"project_configuration"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;resource_environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
    &lt;span class="nx"&gt;resource_location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"euw"&lt;/span&gt;
    &lt;span class="nx"&gt;resource_proj_app_svc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tnp"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aznamingtool_resource_name"&lt;/span&gt; &lt;span class="s2"&gt;"aznt-rg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;components&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;resource_type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rg"&lt;/span&gt;    
    &lt;span class="nx"&gt;resource_instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&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;p&gt;Using this approach, you can easily configure your projects to reuse properties and automate the resource naming generation. To use the name generated from the &lt;em&gt;aznamingtool_resource_name&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"az-rg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aznamingtool_resource_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aznt-rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resource_name&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"West Europe"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your plan result must have similar values:&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;# aznamingtool_resource_name.aznt-rg will be created&lt;/span&gt;
  + resource &lt;span class="s2"&gt;"aznamingtool_resource_name"&lt;/span&gt; &lt;span class="s2"&gt;"aznt-rg"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      + components         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          + &lt;span class="s2"&gt;"resource_environment"&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
          + &lt;span class="s2"&gt;"resource_instance"&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
          + &lt;span class="s2"&gt;"resource_location"&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"euw"&lt;/span&gt;
          + &lt;span class="s2"&gt;"resource_proj_app_svc"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tnp"&lt;/span&gt;
          + &lt;span class="s2"&gt;"resource_type"&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rg"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      + created_on         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + &lt;span class="nb"&gt;id&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + resource_name      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + resource_type_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

 &lt;span class="c"&gt;#azurerm_resource_group.az-rg will be created&lt;/span&gt;
 + resource &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"az-rg"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      + &lt;span class="nb"&gt;id&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + location &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"westeurope"&lt;/span&gt;
      + name     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple example, but both tools are very extensible, and you can configure them to fit your infrastructure requirements. Managing resource names and metadata using tags can help you improve your governance and manage large-scale cloud environments.&lt;/p&gt;

&lt;p&gt;Give a detailed look to both documentation to get know more each one of these tools &lt;a href="https://github.com/mspnp/AzureNamingTool" rel="noopener noreferrer"&gt;AzureNaminTool&lt;/a&gt; &lt;a href="https://registry.terraform.io/providers/rafaelherik/aznamingtool/latest" rel="noopener noreferrer"&gt;aznamintool terraform provider&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>cloudcomputing</category>
      <category>governance</category>
    </item>
    <item>
      <title>Using TruffleHog and pre-commit hook to prevent secret exposure</title>
      <dc:creator>Rafael Herik de Carvalho</dc:creator>
      <pubDate>Thu, 25 Jul 2024 13:20:04 +0000</pubDate>
      <link>https://forem.com/rafaelherik/using-trufflehog-and-pre-commit-hook-to-prevent-secret-exposure-edo</link>
      <guid>https://forem.com/rafaelherik/using-trufflehog-and-pre-commit-hook-to-prevent-secret-exposure-edo</guid>
      <description>&lt;p&gt;In today's landscape of modern software development and distributed teams, Git has become an essential tool for source control. However, a common and recurring issue I've encountered is the inadvertent pushing of secrets to remote repositories. This often necessitates the tedious process of rebasing branches to remove those commits and safeguard credentials from being exposed or stored in the source code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is TruffleHog??&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"TruffleHog™ is a secrets scanning tool that digs deep into your &lt;br&gt;
code repositories to find secrets, passwords, and sensitive keys." &lt;a href="https://trufflesecurity.com/trufflehog" rel="noopener noreferrer"&gt;Read more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TruffleHog is easy to install and use. If you are interested in more features, you can also look at the Enterprise version, but for now, the focus will be on the open-source version to work with git hooks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hands on
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Initializing a Git Repo (Or use your current repo)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir tutorial
$ cd tutorial
$ git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5v6zbo307swbtwxl604g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5v6zbo307swbtwxl604g.png" alt="Creation of the new git repository" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding the code
&lt;/h3&gt;

&lt;p&gt;Here I'm adding a new simple python API that to List Cars from a MySQL database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_db_connection&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;root&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CarDatabase&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/cars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_cars&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_get_db_connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM Cars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cars&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is working, and I'm ready to commit it to my repository. &lt;/p&gt;

&lt;h3&gt;
  
  
  Install TruffleHog
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mac
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;trufflehog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/trufflesecurity/trufflehog" rel="noopener noreferrer"&gt;Here&lt;/a&gt; for Linux and Windows users&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scanning the main.py file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;trufflehog filesystem ./src/main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;2024-07-25T12:06:02+02:00       info-0  trufflehog      running &lt;span class="nb"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"source_manager_worker_id"&lt;/span&gt;: &lt;span class="s2"&gt;"f1VKj"&lt;/span&gt;, &lt;span class="s2"&gt;"with_units"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
2024-07-25T12:06:02+02:00       info-0  trufflehog      finished scanning       &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"chunks"&lt;/span&gt;: 1, &lt;span class="s2"&gt;"bytes"&lt;/span&gt;: 531, &lt;span class="s2"&gt;"verified_secrets"&lt;/span&gt;: 0, &lt;span class="s2"&gt;"unverified_secrets"&lt;/span&gt;: 0, &lt;span class="s2"&gt;"scan_duration"&lt;/span&gt;: &lt;span class="s2"&gt;"3.183166ms"&lt;/span&gt;, &lt;span class="s2"&gt;"trufflehog_version"&lt;/span&gt;: &lt;span class="s2"&gt;"3.80.1"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No secrets were found.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring a Git Hook for pre-commit
&lt;/h3&gt;

&lt;p&gt;I'm using &lt;a href="https://pre-commit.com" rel="noopener noreferrer"&gt;pre-commit&lt;/a&gt;, follow the link to get installation instructions.&lt;/p&gt;

&lt;p&gt;The pre-commit-config.yaml:&lt;br&gt;
&lt;/p&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;local&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;trufflehog&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TruffleHog&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Detect secrets in your data.&lt;/span&gt;
        &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash -c 'trufflehog git file://. --since-commit HEAD --no-verification --fail'&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system&lt;/span&gt;
        &lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;commit"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;push"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the pre-commit-config.yaml, let's install the hook:&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;$ &lt;/span&gt;pre-commit &lt;span class="nb"&gt;install
&lt;/span&gt;pre-commit installed at .git/hooks/pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the repo is ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the hook
&lt;/h3&gt;

&lt;p&gt;I will add a hard-coded secret to test the hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding this piece of code, I need to try to commit:&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;$ &lt;/span&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Try to add a hard-coded secret"&lt;/span&gt;

TruffleHog...............................................................Failed
- hook &lt;span class="nb"&gt;id&lt;/span&gt;: trufflehog
- &lt;span class="nb"&gt;exit &lt;/span&gt;code: 183

🐷🔑🐷  TruffleHog. Unearth your secrets. 🐷🔑🐷

2024-07-25T15:07:13+02:00       info-0  trufflehog      running &lt;span class="nb"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"source_manager_worker_id"&lt;/span&gt;: &lt;span class="s2"&gt;"gWFQC"&lt;/span&gt;, &lt;span class="s2"&gt;"with_units"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
2024-07-25T15:07:13+02:00       info-0  trufflehog      scanning repo   &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"source_manager_worker_id"&lt;/span&gt;: &lt;span class="s2"&gt;"gWFQC"&lt;/span&gt;, &lt;span class="s2"&gt;"unit"&lt;/span&gt;: &lt;span class="s2"&gt;"."&lt;/span&gt;, &lt;span class="s2"&gt;"unit_kind"&lt;/span&gt;: &lt;span class="s2"&gt;"dir"&lt;/span&gt;, &lt;span class="s2"&gt;"repo"&lt;/span&gt;: &lt;span class="s2"&gt;"https://github.com/rafaelherik/demo-trufflehog.git"&lt;/span&gt;, &lt;span class="s2"&gt;"base"&lt;/span&gt;: &lt;span class="s2"&gt;"7e7de59764df7420fc94897219c7dc55bf33a32e"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
Found unverified result 🐷🔑❓
Detector Type: Github
Decoder Type: PLAIN
Raw result: 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
Rotation_guide: https://howtorotate.com/docs/tutorials/github/
Version: 2
Commit: Staged
File: src/main.py
Line: 30
Repository: https://github.com/rafaelherik/demo-trufflehog.git
Timestamp: 0001-01-01 00:00:00 +0000

2024-07-25T15:07:13+02:00       info-0  trufflehog      finished scanning       &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"chunks"&lt;/span&gt;: 2, &lt;span class="s2"&gt;"bytes"&lt;/span&gt;: 212, &lt;span class="s2"&gt;"verified_secrets"&lt;/span&gt;: 0, &lt;span class="s2"&gt;"unverified_secrets"&lt;/span&gt;: 1, &lt;span class="s2"&gt;"scan_duration"&lt;/span&gt;: &lt;span class="s2"&gt;"20.145917ms"&lt;/span&gt;, &lt;span class="s2"&gt;"trufflehog_version"&lt;/span&gt;: &lt;span class="s2"&gt;"3.80.1"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found unverified result
Detector Type: Github
Decoder Type: PLAIN
Raw result: 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
Rotation_guide: https://howtorotate.com/docs/tutorials/github/
Version: 2
Commit: Staged
File: src/main.py
Line: 30
Repository: https://github.com/rafaelherik/demo-trufflehog.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It says the Detector Type is &lt;strong&gt;GitHub&lt;/strong&gt;, and it found a plain text secret in line &lt;strong&gt;30&lt;/strong&gt; on &lt;strong&gt;src/main.py&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Safeguarding sensitive information in code repositories is critical to modern software development. TruffleHog offers a robust solution for detecting and preventing secrets from being inadvertently pushed to remote repositories. &lt;/p&gt;

&lt;p&gt;By integrating TruffleHog with git hooks, developers can automate scanning for sensitive information before committing code, thus enhancing the security of their projects. &lt;/p&gt;

&lt;p&gt;As demonstrated, setting up TruffleHog is straightforward, and its ability to identify hard-coded secrets can significantly mitigate the risk of credential exposure. &lt;/p&gt;

&lt;p&gt;By incorporating such tools into the development workflow, teams can ensure a higher security level and maintain best source control management practices.&lt;/p&gt;

&lt;p&gt;Find this code on &lt;a href="https://github.com/rafaelherik/demo-trufflehog" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading this post!&lt;/p&gt;

&lt;p&gt;I appreciate your interest and hope you found the information useful. Your support and engagement are greatly valued. If you have any questions or feedback, please feel free to leave a comment. Happy coding!&lt;/p&gt;

</description>
      <category>github</category>
      <category>security</category>
      <category>trufflehog</category>
      <category>git</category>
    </item>
  </channel>
</rss>
