Chapter 1: Introduction to Terraform

If you have already worked with Azure, you may know that using the Azure Portal or command line may not be the most effective solution for building an IT infrastructure, particularly in enterprise environments.

Initially, Microsoft promoted the use of Azure Resource Manager (ARM) to build infrastructure declaratively, but ARM templates can be difficult to read. In response, Microsoft introduced Bicep, a new language specifically designed to make it easier to create and maintain ARM templates. However, even with the availability of Bicep and ARM templates, you might still want to consider using an Infrastructure as Code (IaC) tool, such as Terraform, to build your Azure infrastructure. Terraform offers additional benefits, such as version control, reusability, and cross-cloud compatibility, making it a more effective solution for building and managing your Azure infrastructure.

Terraform is an Infrastructure as Code (IaC) tool that allows you to define and manage infrastructure resources using configuration files written in the HashiCorp Configuration Language (HCL). With Terraform, you can use a single configuration file to describe and provision infrastructure resources across a variety of cloud providers and on-premises environments.

When this book was initially drafted, Terraform was licensed under the open-source Mozilla Public License v2.0 (MPL 2.0). However, as of August 10, 2023, HashiCorp announced a transition from the Mozilla Public License v2.0 (MPL 2.0) to the Business Source License (BSL, or BUSL) v1.1 for future releases of all products and several libraries. HashiCorp APIs, SDKs, Terraform providers, and almost all other libraries will remain MPL 2.0. This change means that Terraform is no longer under an open-source license. The BSL 1.1 places certain restrictions on commercial use but generally allows individual users and small-scale projects to use it for free. For more information on this license change, you can refer to HashiCorp Licensing FAQ.

One of the main advantages of using Terraform over Azure Resource Manager (ARM) templates or Bicep templates is that it is multi-cloud and multi-platform, meaning that it can manage resources across a variety of cloud providers and on-premises environments. This can be particularly useful if you need to manage resources across multiple cloud providers or if you want to have a consistent approach to infrastructure management across different environments.

Another advantage of Terraform is its large and active community of users, which means that it is constantly being updated and improved. Terraform also has a rich ecosystem of plugins and integrations that can be used to extend its capabilities and make it easier to work with.

In comparison, ARM templates are specific to Azure and are used to define and deploy Azure resources. Bicep templates are a new language specifically designed for defining ARM templates in a more concise and easier-to-read format. While both ARM templates and Bicep templates are useful tools for managing Azure resources, they are limited to Azure and do not offer the same level of flexibility and cross-platform support as Terraform.

Overall, Terraform is a powerful and flexible tool that can manage infrastructure resources across a variety of cloud providers and on-premises environments. Its multi-cloud and multi-platform capabilities, active community, and rich ecosystem of integrations make it a popular choice for Infrastructure as Code.

How to install Terraform?

Terraform provides several installation methods, and you can choose the one that best fits your needs. These methods are documented in the official documentation. Personally, I prefer the manual installation method over installing Terraform through a package manager, as it allows me to specify a specific version of Terraform for my user only. In this tutorial, I will demonstrate how to manually install Terraform on Ubuntu 22.04 and ensure that $HOME/bin is included in your $PATH.

TERRAFORM_VERSION="1.10.5"
INSTALL_DIR="$HOME/bin/terraform_$TERRAFORM_VERSION"
mkdir -p $INSTALL_DIR
wget -q https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip -O /tmp/terraform.zip
unzip -d $INSTALL_DIR /tmp/terraform.zip && rm /tmp/terraform.zip
chmod +x $INSTALL_DIR/terraform

# Add the specific version directory to PATH
if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
    echo "export PATH=$INSTALL_DIR:\$PATH" >> $HOME/.bashrc
    source $HOME/.bashrc
fi

terraform -version

# Output:
# Terraform v1.10.5
# on linux_amd64

How to use Terraform for Azure?

Once you have installed Terraform on your development environment, you can begin writing Terraform code to manage your Azure resources. However, before you can do this, you will need to authenticate Terraform with your Azure subscription. There are several ways to do this, as described in the official Azure documentation.

  1. Service principal with a secret: You can create a service principal in Azure Active Directory and assign it the necessary permissions to manage your Azure resources. You can then use the service principal's client ID and client secret to authenticate Terraform.

  2. Service principal with a certificate: Alternatively, you can create a service principal and assign it a certificate instead of a secret. You can then use the certificate to authenticate Terraform.

  3. Managed identity: If you are running Terraform on an Azure resource that has a managed identity (such as an Azure Virtual Machine or Azure Functions), you can use the managed identity to authenticate Terraform.

  4. Azure CLI: You can use the Azure CLI to authenticate and set the necessary environment variables for Terraform to use.

  5. Azure Cloud Shell: If you are using Azure Cloud Shell, you can use the built-in authentication to authenticate Terraform.

The most common method is using Service principal with a secret, as shown below:

export ARM_CLIENT_ID=your_client_id
export ARM_CLIENT_SECRET=your_client_secret
export ARM_SUBSCRIPTION_ID=your_subscription_id
export ARM_TENANT_ID=your_tenant_id

If you are using the Azure CLI to authenticate Terraform, you will need to run the authentication commands each time you open a new terminal session. To make this process more convenient, you can create an alias in your development environment that sets the necessary environment variables and sources them automatically. For example, you could create a file called azure-auth.sh with the following contents:

!/bin/bash
export ARM_CLIENT_ID=your_client_id
export ARM_CLIENT_SECRET=your_client_secret
export ARM_SUBSCRIPTION_ID=your_subscription_id
export ARM_TENANT_ID=your_tenant_id

For example, if you are using the Bash shell, you can add the following line to your ~/.bashrc or ~/.bash_aliases file:

alias azure-auth='. /path/to/azure-auth.sh'

Now, you can simply run the azure-auth alias to set the necessary environment variables and authenticate Terraform with the Azure CLI.

Terraform Ground Rules

Terraform is a great tool, but it's important to follow some best practices, especially if you have a team of developers working on your infrastructure code. Before you start using Terraform, I recommend setting some guidelines for your team to follow. For example, you might want to establish conventions for naming resources and organizing your configuration files. This can help you avoid issues like unintentionally destroying and recreating resources when you make changes. By following these guidelines, you'll be able to work more efficiently and effectively with Terraform in your team.

Here are some best practices for working with Terraform in a team:

  1. Terraform directory structure: It is important to maintain a consistent directory structure for all of your Terraform projects, especially when you are provisioning multiple environments like DEV, PREPROD, or PROD. There are various approaches to organizing your directories, and in the following chapters, we will discuss the one I recommend.

  2. Terraform module structure: You should also follow a structured approach when creating modules, and it is recommended to create a module for almost everything. Terraform provides a great guideline for module structure, which you should consider following.

  3. Resource/module naming convention: If you are creating a new resource or module, it is important to establish a naming standard to follow. Terraform will not allow you to change the name of a resource or module without recreating the infrastructure component, unless you manually edit your state file or use moved block in your code.

  4. State file key convention: Your state file may be referenced by other Terraform codes, so it is important to have a naming convention for your state file resources and keys.

  5. Terraform output convention: The output of your Terraform code, especially for modules, is important as it will be referenced by other Terraform codes using those modules as input. Be sure to establish a naming convention for your outputs.

  6. Lifecycle of resources: Each resource you build should have a defined lifecycle, especially for stateful resources. It is important to ensure that they are not accidentally deleted or recreated with Terraform. Lifecycle of resources is especially useful if you have Azure Policies applied to each created resource. You can use lifecycles to prevent Terraform from reverting the changes applied by the policies.

  7. Coding Format and Style: When working on a Terraform codebase as a team, consistency in indentation and syntax is crucial. To ensure that everyone adheres to the same guidelines, consider using Git pre-commit hooks with the terraform fmt [-recursive] command. This will apply the suggested Terraform indentation automatically.

Last updated