Elevating IaC Workflows with Spacelift Stacks and Dependencies 🛠️

Register for the July 23 demo →

Terraform

Terraform Architecture Overview – Structure and Workflow

Architecture of Terraform

In this article, we will explore Terraform, a widely used Infrastructure as Code (IaC) tool. We will provide an overview of Terraform, its objectives, fundamental architecture, and the workflow that encompasses the different stages of provisioning infrastructure with Terraform. We will also highlight the advantages of using Terraform over other cloud-native infrastructure tools.

Terraform is an open-source tool developed by Hashicorp that enables you to provision your infrastructure in a simple, efficient, and declarative manner through repeatable code, whether it be on cloud or on-premises environments.

One of Terraform’s key features is its cloud-agnostic nature; you can deploy infrastructure to any cloud environment, such as Azure, AWS, GCP, and VMware, as well as on-premises environments. This benefit allows you to automate your cloud infrastructure without having to learn or adopt different tools for each cloud service provider.

Architecture of Terraform

Terraform architecture mainly consists of the following components:

  • Terraform Core
  • Providers
  • State file

Below you can see the Terraform architecture diagram.

terraform architecture diagram

Terraform Core

Terraform’s core (also known as Terraform CLI) is built on a statically-compiled binary that’s developed using the Go programming language.

This binary is what generates the command line tool (CLI) known as “terraform,” which serves as the primary interface for Terraform users. It is open source and can be accessed on the Terraform GitHub repository.

Providers

Terraform providers are modules that enable Terraform to communicate with a diverse range of services and resources, including but not limited to cloud providers, databases, and DNS services. 

Each provider is responsible for defining the resources that Terraform can manage within a particular service and translating Terraform configurations into API calls that are specific to that service.

Providers are available for numerous services and resources, including those developed by major cloud providers like AWS, Azure, and Google Cloud, as well as community-supported providers for various services. By utilizing providers, Terraform users can maintain their infrastructure in a consistent and reproducible manner, regardless of the underlying service or provider. 

State file

The Terraform state file is an essential aspect of Terraform’s functionality. It is a JSON file that stores information about the resources that Terraform manages, as well as their current state and dependencies. 

Terraform utilizes the state file to determine the changes that need to be made to the infrastructure when a new configuration is applied. It also ensures that resources are not unnecessarily recreated across multiple runs of Terraform. 

The state file can be kept locally on the machine running Terraform or remotely using a remote backend like Azure Storage Account or Amazon S3, or HashiCorp Consul. It is crucial to safeguard the state file and maintain frequent backups since it contains sensitive information about the infrastructure being managed.

Note: New versions of Terraform will be placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that will expand on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6. OpenTofu retained all the features and functionalities that had made Terraform popular among developers while also introducing improvements and enhancements. OpenTofu works with your existing Terraform state file, so you won’t have any issues when you are migrating to it.

Terraform Structure

Declaring resources is very easy in Terraform. Terraform files always end with the extension .tf.

The basic Terraform structure contains the following elements.

Terraform Block

A Terraform block specifies the required providers that terraform needs in order to execute the script. This block also contains the source block that specifies from where terraform should download the provider and also the required version.

Below is an example:

terraform { 
  required_providers { 
    azurerm = { 
      source  = "hashicorp/azurerm" 
      version = "=3.0.0" 
    } 
  } 
}

Provider Block

A provider block specifies the cloud provider and the API credentials required to connect to the provider’s services. It includes the provider name, version, access key, and secret key.

For example, if you are using Azure as your service provider, it would look as follows:

provider "azurerm" {
  features {}
  subscription_id = "00000000-0000-0000-0000-000000000000"
  tenant_id = "11111111-1111-1111-1111-111111111111"
}

Resource Block

A resource block represents a particular resource in the cloud provider’s services. It includes the resource type, name, and configuration details. This is the main block that specifies the type of resource we are trying to deploy.

Below is an example for creating a resource group in Azure.

resource "azurerm_resource_group" "example" { 
  name = "example" 
  location = "West Europe" 
}

Data Block

A data block is used to fetch data from the provider’s services, which can be used in resource blocks. It includes the data type and configuration details.

This is used in scenarios where the resource is already deployed, and you would like to fetch the details of that resource.

The code snippet below helps you to fetch details of an existing resource group that is already deployed.

data "azurerm_resource_group" "example" { 
  name = "existing" 
}

Variable Block

A variable block is used to define input variables that are used in the Terraform configuration. It includes the variable name, type, and default value.

Following is an example of a variable block in Terraform.

variable "resource_group_name" {
  default = "myTFResourceGroup"
}

Output Block

An output block is used to define output values that are generated by the Terraform configuration. It includes the output name and value.

output "resource_group_id" {
  value = azurerm_resource_group.rg.id
}

Provisioners

Terraform provisioners are a feature that allows Terraform to execute scripts or commands on newly created resources or instances. These scripts can be used for various purposes, such as setting up and configuring the infrastructure, installing software, running tests, and performing any other necessary actions. 

Provisioners are executed after a resource has been created and can also be triggered when a resource is destroyed. Terraform comes with several built-in provisioners, including the file provisioner for copying files to a resource and the remote-exec provisioner for running commands on a remote machine. It is also possible to create custom provisioners for more advanced use cases. 

This is mainly used as a last resort unless you are unable to achieve your desired outcome with existing resource blocks in Terraform.

Terraform Workflow

Terraform workflow is the set of steps and actions that a user follows to manage infrastructure using Terraform. 

Following are the general steps that are involved in the lifecycle of a resource creation:

  1. Define: Author your Infrastructure as Code in a Terraform configuration file with all the required blocks.
  2. Initialize: Initialize the Terraform working directory and download any necessary plugins. This is usually done using terraform init command.
  3. Review: Review the Terraform execution plan to see what changes will be made to the infrastructure. This is done using the terraform plan command. Running this command will show the actions that Terraform is going to perform when terraform apply command is run.
  4. Apply: Apply the changes to create or modify the infrastructure. Once you are comfortable with the changes that are shown in the output of terraform plan command, you can apply those changes using terraform apply command.
  5. Inspect: You can Inspect the state of the infrastructure using the Terraform state file.

In case you need to apply any new configuration, make the necessary changes in the config and follow the above steps to apply the configuration.

These steps are often repeated as part of a Continuous Integration/Continuous Delivery (CI/CD) pipeline or as part of ongoing infrastructure management. Terraform’s declarative approach to infrastructure as code allows for a consistent and reproducible workflow, where infrastructure changes can be tracked, reviewed, and audited over time.

If you want to have all the Terraform commands in one place, check out our Terraform Cheat Sheet.

We encourage you also to explore how Spacelift makes it easy to work with Terraform. If you need any help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a fantastic tool for this.

Key Points

This blog post covered several key topics related to Terraform and delved into the Terraform template structure and architecture, including the Terraform core and provisioners. Additionally, the post discussed the various steps involved in Terraform’s workflow. Thank you for reading!

Automate Terraform Deployments with Spacelift

Automate your infrastructure provisioning, and build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization, and many more.

Start free trial

How can Spacelift stacks & dependencies elevate your IaC workflows?

Don’t miss our July 23 webinar.

Register for the webinar