Terraform and IaC: Managing Infrastructure as Code on AWS, GCP, and Azure
Imagine being able to deploy an entire production cluster of dozens of servers, load balancers, and databases with a single command. No console, no manual clicking, no risk of human error. This is exactly what Infrastructure as Code (IaC) provides, and Terraform is the leading tool in this ecosystem. In 2026, when cloud environments have become the de facto standard, the ability to manage resources through code is not a luxury but a necessity for any DevOps engineer.
What is Terraform and Why Has It Become the IaC Standard?
Terraform by HashiCorp is an open-source tool for declaratively describing infrastructure. Unlike Ansible or Puppet, which focus on configuring already running servers, Terraform manages the lifecycle of the resources themselves: creating, modifying, and deleting them. Its main feature is providers. These are plugins that allow interaction with any cloud's API: AWS, Microsoft Azure, Google Cloud Platform, as well as on-premises solutions like VMware or OpenStack.
The key idea of Terraform is declarative approach. You write what the infrastructure should look like (the desired state), and Terraform itself calculates what steps are needed to transition from the current state to the desired one. This is fundamentally different from the imperative approach, where you describe a sequence of actions.
Terraform State: The Heart of Infrastructure Management
When you run terraform apply, the tool creates a state file. This is a JSON file that contains a mapping between your code and the actual resources in the cloud. The state is the "source of truth." Without it, Terraform doesn't know what has already been created and what needs to be deleted.
Why Should State Be Stored Remotely?
If the state is stored locally (on your laptop), you risk:
- Losing it if your disk fails.
- Creating version conflicts if a team works on the infrastructure.
- Accidentally deleting an important resource by running terraform destroy on an old version of the state.
It is recommended to use remote backends: S3 (AWS) with DynamoDB for locking, GCS (GCP), or Azure Storage. This ensures centralized storage, versioning, and security.
Providers: AWS, GCP, Azure — How to Choose and Configure?
Terraform supports hundreds of providers. For the cloud giants, configuration is trivial:
| Provider | Configuration File | Authentication |
|---|---|---|
| AWS | provider "aws" { region = "us-east-1" } |
Environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY or IAM role |
| GCP | provider "google" { project = "my-project" } |
Service account .json file or GOOGLE_APPLICATION_CREDENTIALS |
| Azure | provider "azurerm" { features {} } |
Azure CLI or Service Principal |
Example of a multi-cloud configuration:
provider "aws" {
region = "eu-west-1"
}
provider "google" {
project = "my-gcp-project"
region = "europe-west1"
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
resource "google_compute_instance" "web" {
name = "web-server"
machine_type = "e2-micro"
zone = "europe-west1-b"
}
Modules: Reusability and Scaling
Writing the entire infrastructure in a single main.tf file is bad practice for production. Modules allow you to group resources into logical blocks and reuse them. For example, a vpc module can create a virtual network, subnets, and gateways, while an eks module can create a Kubernetes cluster.
Example Project Structure:
infrastructure/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── ec2/
│ ├── main.tf
│ └── variables.tf
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ └── prod/
│ ├── main.tf
│ └── terraform.tfvars
└── global/
└── s3-backend.tf
Modules can be published to the Terraform Registry
Comments