- Manage Azure Policy using Terraform - Tue, Aug 2 2022
- Getting started with Terraform in Azure - Tue, Jul 12 2022
- Azure Bicep: Getting started guide - Fri, Nov 19 2021
In particular, you'll learn about:
- Terraform cross-platform versatility
- Terraform deployment workflow
- Terraform providers, modules, and state files
- Writing a Terraform configuration
- Deploying a Terraform configuration to Azure
Prerequisites
To follow along with this tutorial, you will need:
- An Azure tenant and access to a subscription, such as Owner or Contributor rights
- VS Code or other IDE. However, VS Code has a Terraform extension to improve the authoring process
What is Terraform?
Terraform is a popular tool for deploying and managing cloud and other infrastructure environments. Terraform uses the HashiCorp Configuration Language (HCL) to define resources, retrieve data, and import plugins. Instead of writing scripts to deploy resources, you write out the desired state of your topology, and Terraform does the heavy lifting of figuring out how to deploy it.
Terraform is vendor agnostic, meaning it works on multiple platforms. These platforms include cloud providers, such as Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP), and on-premises platforms, such as VMware vSphere and OpenStack.
Terraform's versatility comes from its many providers. Providers interact with these different cloud platforms and services through their application programming interfaces (APIs). If the platform has an accessible API, Terraform can interact with the API through a custom provider.
HashiCorp and the Terraform community have written over 2200 providers to work with many different types of platforms and services. These providers include AWS, Azure, GCP, Kubernetes, GitHub, Splunk, and more. HashiCorp makes these providers available through the Terraform Registry.
Terraform uses the .tf file extension for most of its files. You may also see a JSON-based variant that uses the .tf.json file extension.
Terraform workflow
Terraform uses a three-stage workflow for deploying resources and using providers.
- Write: You define resources in a Terraform configuration. A Terraform configuration is one or more files and directories written in HCL. This configuration informs Terraform of how to deploy and manage a set of infrastructure resources. For example, you create a configuration for deploying a virtual network, virtual machines, and a load balancer into a cloud service.
- Plan: Terraform examines the current infrastructure and creates a plan. This plan describes the changes Terraform will make based on the configuration. These changes can include creating new resources, updating existing resources, or destroying resources.
- Apply: Terraform applies the plan changes to the infrastructure in the correct order. For example, if a virtual machine relies on a virtual network, Terraform deploys the virtual network first, and then any dependent resources. Terraform automatically determines resource dependencies.
Terraform state file
Terraform manages infrastructure and configuration through a state file. This state file maps resources to your design. Terraform uses the state file to create plans and make the proposed changes to your infrastructure. Terraform updates the state file during the Apply portion of the workflow. The state file also stores metadata about the resources, such as dependencies.
By default, Terraform stores the state file in the working directory in which you run Terraform. Terraform names the state file "terraform.tfstate." Remote states allow teams to share a common state file so that everyone can work with the same remote objects. You should never edit the state file directly; instead, there are Terraform commands to remove or import resources.
Terraform supports remote storage of the state file in shared storage. Terraform locks the remote state file during deployment to prevent multiple users from making changes simultaneously. Remote state locking ensures that the following user has the latest changes when planning and applying their configuration. Supported remote states include Terraform Cloud, HashiCorp Consul, Amazon S3, Azure blob storage, Google Cloud Storage, and many more.
Terraform modules
Terraform supports the use of modules. A module is a configuration that deploys one or more resources in a standardized fashion. Modules are a way to package and reuse configurations in Terraform. A module includes any .tf files stored in the same directory.
For example, when deploying a virtual machine in Azure, you create a network interface card (NIC), provision data disks, and define the compute resource. A module includes creating all these resources together to make the process easier. You call the module and pass in argument values for properties such as operating system, number of disks, and the virtual network to place the virtual machine.
In addition to providers, the Terraform registry contains a vast collection of public modules. These modules are also free to use, and Terraform downloads them automatically if you specify the correct source and version when calling the module.
Terraform editions
HashiCorp offers three different Terraform editions to meet your organization's needs.
Terraform Open Source
The open-source version of Terraform is a free tool you can download. The open-source executable allows you to interact with Terraform using the command line. Using the open-source version, you can deploy to any cloud provider and manage configurations, plugins, infrastructure, and state files.
The open-source version is excellent if you are learning Terraform. You write and deploy Terraform configurations from your local computer system. You can also use the open-source version with tools such as GitHub Actions and Azure DevOps Pipelines.
Terraform Cloud
Terraform Cloud is HashiCorp's Software-as-a-Service (SaaS) offering that runs Terraform in a stable, remote environment. Terraform Cloud also securely stores your state file and hosts a private registry for your custom modules.
You can also connect to version control systems (VCS), such as GitHub, GitLab, BitBucket, and Azure DevOps. New commits and changes to connected repositories can automatically trigger a Terraform plan. Terraform Cloud offers many free features to individuals or small teams. Larger organizations with additional collaboration and governance needs can purchase a paid plan.
Terraform Enterprise
Terraform Enterprise is a self-hosted distribution of HashiCorp's Terraform Cloud product. Terraform Enterprise allows you to set up a private instance of Terraform Cloud with dedicated support from HashiCorp. Organizations with strict security and compliance requirements typically deploy Terraform Enterprise.
Terraform configuration components
There are a few essential items to configure when writing a Terraform configuration. The following example covers how to deploy a resource group and storage account in the Azure cloud. For this tutorial, create two files: main.tf for storing the configuration code, and variables.auto.tfvars for storing variable values.
Providers
To work with providers to interact with remote systems, you must declare which providers to use. The provider block sets the provider source and version you need.
Start by creating a top-level terraform block in the main.tf file. Add a nested required_providers block containing the provider's local name, source location, and version constraint. In this example, the local name is azurerm, the source is "hashicorp/azurem", and the version is "3.0.0". You can set minimum or maximum versions using greater than (>) or less than (<) syntax. Learn more about setting versions here.
After defining the required providers, the features block configures the resource behavior of the azurerm provider. For example, you can enable Terraform to delete an OS disk when Terraform destroys the virtual machine resource. If you want to use the default behaviors of the azurerm provider, define an empty features block, as shown in the example below. Learn more about the features block here.
terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.0.0" } } } provider "azurerm" { features {} }
Variables
Like most programming and configurations, Terraform uses variables. Variables allow the reuse of the same Terraform configuration in different scenarios. You can use the same configuration to deploy to different regions or different environments, such as development or production.
Several types of variables can be used, such as strings, Booleans, numbers, lists, maps, or objects. Use the keyword variable to define a variable, followed by the variable name. In the variable block, define the type, description, and default value, if desired.
In this example, define two string variables: location and prefix. You will use location for deploying resources, and prefix is used in naming resources.
variable "location" { type = string default = "West US 2" } variable "prefix" { type = string default = "4sysops" }
In your variables.auto.tfvars file, set the value for the two variables. In this example, the location is "West US 2", and the prefix is "4sysops".
location = "West US 2" prefix = "4sysops"
Resources
The power of Terraform comes from defining resources for your environment. You define resources using the resource keyword, followed by the resource type and symbolic name. In the resource block, you define the resource properties using arguments. The basic structure of a resource block looks like this:
resource "<resource type>" "<symbolic name>" { <property> = <argument> }
Resources don't always have to represent a part of the environment or infrastructure. For example, you can generate a random number for naming a storage account. Use the resource type "random_integer" followed by a symbolic name for the integer ("sa_id"). The "random_integer" resource has two properties, min and max, which define the range the number should be.
resource "random_integer" "sa_id" { min = 1000 max = 9999 }
Next, define a resource group to hold a storage account. The resource type is "azurerm_resource_group", and the symbolic name is "rg". A resource group requires two properties: name and location. In this example, the resource group name is "tfdemo-rg", and the location is set to the value of the location variable.
resource "azurerm_resource_group" "rg" { name = "tfdemo-rg" location = var.location }
Finally, define the storage account resource using the "azurerm_storage_account" resource type. The storage account has five required properties. For the storage account name, use interpolation with the prefix variable and the string "stgacct." Interpolation inserts the variable value along with the rest of the string. You also reference the output of the random_integer resources using the resource type (randominteger), symbolic name (said), and ID property (.id).
For the resource_group_name and location properties, reference the resource group you defined earlier using the resource type and symbolic name.
You are creating an implicit dependency by referencing the resource group this way. Terraform then knows it should make the resource group before creating the storage account. By referencing its ID property, you also have an implicit dependency on the random_integer resource.
Finally, set the account_replication_type to "LRS" (locally redundant storage) and the account_tier to "Standard".
resource "azurerm_storage_account" "sa" { name = "${var.prefix}stgacct${random_integer.sa_id.id}" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location account_replication_type = "LRS" account_tier = "Standard" }
Outputs
You can also output information from a Terraform configuration. Terraform displays this information after it has applied the configuration. Information could include a public IP address assigned to a virtual machine or a resource ID. You can pass information from one module to another using outputs.
Output definitions follow the same format as defining a variable. Use the output keyword, followed by naming the output and setting the value. In this example, the output name is sa_name, and the value is the name attribute associated with the azurerm_storage_account.sa resource.
output "sa_name" { value = azurerm_storage_account.sa.name }
You can view the full main.tf and variables.auto.tfvars files in the 4sysops_tf_guide GitHub repository for reference.
Deploying Terraform configurations in Azure
With your Terraform configuration completed, it is time to deploy it to Azure. Before continuing, you will need to install the Terraform open-source binary on your system. Follow the Install Terraform guide from Terraform for your operating system.
Azure authentication
To deploy your Terraform configuration, you need to authenticate to Azure. While there are many ways to authenticate to Azure, this tutorial uses the Azure CLI method.
To authenticate using Azure CLI:
- Run the az login command and authenticate using your web browser.
- If necessary, select the subscription where you want to deploy the Terraform configuration using the az account set command. This example uses a subscription named Demo.
az account set --subscription "Demo"
Prepare the deployment
Next, you initialize, validate, and create a plan for your Terraform configuration:
- Open your shell environment, and navigate to the directory in which you saved the configuration files.
- Use the terraform init command to initialize your working directory. The init command downloads any modules or providers you defined in the configuration.
- Run the terraform validate command to verify configuration files and syntax in the working directory. Resolve any issues the command finds.
- Run the terraform plan command to see what changes Terraform will make using the configuration.
terraform init terraform validate terraform plan
Here are some screenshots showing the plan output. Notice that some resource properties are not known until Terraform creates them. At the end of the plan command output, Terraform shows that it will create three resources: the random integer, the resource group, and the storage account. You also see that Terraform will output the sa_name.
Deploy configuration
With everything in place, you are now ready to deploy the configuration to Azure.
- Use the terraform apply command to apply your configuration.
- Terraform will run another plan to verify the resources from the configuration. Review the output and verify it for accuracy.
- Terraform will prompt to perform the actions. Enter 'yes' to continue the deployment.
- Terraform displays the deployment results; in this case, three resources and the name of the dynamically generated storage account were created.
Congratulations! You just wrote your first Terraform configuration and deployed it to Azure.
Subscribe to 4sysops newsletter!
Conclusion
Terraform is a popular cross-platform IaC tool for deploying and managing infrastructure. It is easy to get started with Terraform by downloading the open-source executable and deploying configurations from your local system. In this tutorial, you learned about the basics of Terraform, including the deployment workflow and writing your first configuration. Now it's time to get rid of your deployment scripts and start deploying using Terraform!
This is good information. I did use terraform while integrating Secureworks XDR with Azure AD.