Terraform

Bhagya-patelBhagya-patel
16 min read

🔹What is Terraform ?

Terraform is an open-source Infrastructure as Code (IaC) tool created by HashiCorp. It allows you to automate the creation, management, and destruction of infrastructure (servers, networks, databases, etc.) using declarative configuration files.

🔹Challenges in IT Structure

🔹Why use Terraform?

  • ✅ Automates infrastructure provisioning
    (No need to click manually in AWS/Azure/GCP console repeatedly)

  • ✅ Infrastructure as Code (IaC)
    Write .tf files to define your infrastructure like code, version it in Git.

  • ✅ Cloud agnostic
    Supports AWS, Azure, GCP, OCI, VMware, Kubernetes, and many more.

  • ✅ Idempotent
    Running the same code repeatedly will not create duplicate resources.

  • ✅ Plan before you apply
    You can preview what will change before applying using terraform plan.

🔹What can you do with Terraform?

Using Terraform, you can:

  • Create EC2 instances on AWS

  • Configure VPCs, subnets, security groups

  • Spin up Kubernetes clusters

  • Deploy serverless functions

  • Manage DNS records

  • Provision databases

  • and much more…

All automatically, consistently, and repeatably.

🔹How does Terraform work?

1️⃣ Write Configuration
You write .tf files using HashiCorp Configuration Language (HCL) to describe what infrastructure you want.

2️⃣ Initialize
terraform init initializes your working directory.

3️⃣ Plan
terraform plan shows what will be created, changed, or destroyed.

4️⃣ Apply
terraform apply actually makes the changes on your cloud provider.

5️⃣ Destroy
terraform destroy will clean up all resources when you no longer need them.

🔹 Terraform vs Ansible

AspectTerraformAnsible
PurposeInfrastructure ProvisioningConfiguration Management (and some provisioning)
TypeDeclarative IaCProcedural (imperative) and declarative
Primary UseCreate, modify, destroy infrastructure (VMs, networks, databases)Configure software and environments on provisioned servers
LanguageHCL (HashiCorp Configuration Language)YAML (Playbooks)

🔹Setup on AWS EC2

copy ssh and paste it on your local

go to here:-

https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli

go to there and copy it and paste it on your EC2 server

🔹Setup on Local (Windows)

go to here:-

https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli

after open terminal with Run as Administrate state

🔹Terraform HCL in Depth

✅What is Blocks ?

A block in Terraform is a container for configuration, using this structure:

<block_type> "<label1>" "<label2>" {
    key1 = value1
    key2 = value2
}

It defines a piece of Terraform configuration such as a provider, resource, variable, output, or module.

✅ Examples of blocks

1️⃣ Provider block – configures the provider:

hclCopyEditprovider "aws" {
  region = "ap-south-1"
}

2️⃣ Resource block – creates infrastructure resources:

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

3️⃣ Variable block – declares input variables:

variable "instance_count" {
  type    = number
  default = 2
}

4️⃣ Output block – prints output values:

output "instance_ip" {
  value = aws_instance.example.public_ip
}

✅Blocks and Arguments

A block is a container for other content and An argument assigns a value to a particular name:

filename = "/home/ubuntu/abc123.txt"

The identifier before the equals sign is the argument name, and the expression after the equals sign is the argument's value.

Resource block: block name used to mention the type of the block. The resource block expects two labels, which are local_file and “pet” in the example above. A particular block type may have any number of required labels, or it may require none.

resource “<provider>_ <resource type> “<resource name>” {

Argument1 = “”

Argument2=””

}

Local = provider, file = type, “pet” name of the resource.

Then we have arguments, filename, content, etc

We can have multiple resources

resource "random_string" "rand-str" {

length = 16

special = true

override_special = "!#$%&*()-_=+[]{}<>:?"

}

output "rand-str" {

value = random_string.rand-str[*].result

}

✅Execution of Infrastructure

1️⃣ Write Configuration
You write .tf files using HashiCorp Configuration Language (HCL) to describe what infrastructure you want.

2️⃣ Initialize
terraform init initializes your working directory.

3️⃣ Plan
terraform plan shows what will be created, changed, or destroyed.

4️⃣ Apply
terraform apply actually makes the changes on your cloud provider.

5️⃣ Destroy
terraform destroy will clean up all resources when you no longer need them.

✅ Practical

now, terraform init is like setting up your coding environment before you start coding.

terraform validate

for check your configration is right.

terraform apply

terraform destroy

terraform apply -auto-approve

✅ Skips the approval prompt
✅ Applies the changes immediately without asking.

terraform destroy -auto-approve

here local is provider.

resource “<provider>_ <resource type> “<resource name>” {

Argument1 = “”

Argument2=””

}

✅ What is a provider in Terraform?

A provider in Terraform is a plugin that allows Terraform to interact with APIs of external platforms and services, such as:

  • AWS

  • Azure

  • Google Cloud

  • GitHub

  • Kubernetes

  • Cloudflare

Providers manage the lifecycle of resources (create, read, update, delete) in these services.

✅ Why is it needed?

Terraform itself is generic and does not know how to interact with specific platforms.
Providers tell Terraform how to manage resources on a specific platform.

Example:

  • You want to create an EC2 instance on AWS ➔ you need the AWS provider.

  • You want to create a GKE cluster on GCP ➔ you need the Google provider.

🔹practical:- s3 bucket create

Here, we do not have the AWS provider.

So first, we have to install the AWS provider and configure the environment.

go to here:- https://registry.terraform.io/providers/hashicorp/aws/latest/docs

after go to on the use provider

copy it and paste it on terraform.tf

after it use terraform init

Now we have the AWS provider, so Terraform gives us a tool to connect to AWS. But it doesn’t know which account to connect to, so we need the AWS CLI.

so first install AWS CLI.

What is AWS CLI?

The AWS CLI (Command Line Interface) is a tool provided by AWS that allows you to interact with AWS services directly from your terminal/command prompt using commands, instead of using the AWS Management Console.

✅install for windows

✅install for Linux

go to here:- https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

copy and paste commands

now for unzip it we have to install unzip tool

now finally we installed AWS CLI.

but now we have to need a AWS Access Key ID

in this first we create a USER. so click on under user

also paste secret access key

now checkout region of AWS

🔹practical:- EC2 Instance created on local

now we install terraform provider for local

AWS

first take a key pair

go to here:- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair

check how write

now take a VPC. here we take a default VPC

go to here:- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_vpc

now take security group

go to here:- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group

show here for inbound rule port is 22 . and protocol is TCP.

cidr_blocks means source

code:-

# Key Pair (for SSH login)

resource "aws_key_pair" "my_key" {

key_name = "terra-key-ec2"

public_key = file("terra-key-ec2.pub")

}

# Default VPC

resource "aws_default_vpc" "default" {

}

# Security Group

resource "aws_security_group" "my_secure_group" {

name = "automate-sg"

description = "This will add a TF generated security group"

vpc_id = aws_default_vpc.default.id

# Inbound rule: SSH

ingress {

from_port = 22

to_port = 22

protocol = "tcp"

cidr_blocks = ["0.0.0.0/0"]

description = "SSH open"

}

# Inbound rule: HTTP

ingress {

from_port = 80

to_port = 80

protocol = "tcp"

cidr_blocks = ["0.0.0.0/0"]

description = "HTTP open"

}

# Outbound rule: Allow all

egress {

from_port = 0

to_port = 0

protocol = "-1"

cidr_blocks = ["0.0.0.0/0"]

description = "All access open outbound"

}

tags = {

Name = "automate-sg"

}

}

now we create ec2 instance

go to here:- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/instance

for ami id first go to provide.tf and check what region you choose . after go to on the aws and select that region

if you create ubuntu then choose ubuntu and show what is AMI ID

after it

Here, it is a root_block_device. We specify the root volume storage with volume_size = 8 and volume_type = gp3.

FULL CODE:-

# Key pair

resource "aws_key_pair" "my_key" {

key_name = "terra-key-ec2"

public_key = file("terra-key-ec2.pub")

}

# Default VPC

resource "aws_default_vpc" "default" {

}

# Security Group

resource "aws_security_group" "my_secure_group" {

name = "automate-sg"

description = "TF-generated security group"

vpc_id = aws_default_vpc.default.id

# Inbound rule for SSH

ingress {

from_port = 22

to_port = 22

protocol = "tcp"

cidr_blocks = ["0.0.0.0/0"]

description = "SSH open"

}

# Inbound rule for HTTP

ingress {

from_port = 80

to_port = 80

protocol = "tcp"

cidr_blocks = ["0.0.0.0/0"]

description = "HTTP open"

}

# Outbound rule (allow all)

egress {

from_port = 0

to_port = 0

protocol = "-1"

cidr_blocks = ["0.0.0.0/0"]

description = "All outbound access open"

}

tags = {

Name = "automate-sg"

}

}

# EC2 Instance

resource "aws_instance" "my_instance" {

ami = "ami-01f23391a59163da9" # Ubuntu

instance_type = "t2.micro"

key_name = aws_key_pair.my_key.key_name

security_groups = [aws_security_group.my_secure_group.name]

root_block_device {

volume_size = 15

volume_type = "gp3"

}

tags = {

Name = "bhagya-terraform-automate"

}

}

here we last used a tages that is from here

it shows this error.

so we give it to permission

attach AdministrateAccess

after go on the permission boundary ans set it to Administrator access

🔹Variables

🚩 What are variables in Terraform?

Variables in Terraform allow you to:
✅ Avoid hardcoding values (AMI ID, instance type, region, etc.).
✅ Reuse configurations across environments.
✅ Make your Terraform code clean, flexible, and scalable.

📌 Types of variables:

1️⃣ Input Variables (variable)
Used to pass values into modules/configurations.

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t2.micro"
}

2️⃣ Output Variables (output)
Used to display values after applying.

output "instance_public_ip" {
  description = "Public IP of the EC2 instance"
  value       = aws_instance.bhagya_instance.public_ip
}

3️⃣ Local Values (locals)
Used for intermediate calculations or to simplify complex expressions.

locals {
  bucket_name = "${var.env}-project-bucket"
}

🚀 How to use input variables practically

1️⃣ Declare a variable

In your variables.tf :

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t2.micro"
}

2️⃣ Use the variable in your main(main.tf) file

In your main.tf:

resource "aws_instance" "bhagya_instance" {
  ami           = "ami-020cba7c55df1f615"
  instance_type = var.instance_type
}

🚀Practical:-

here change t2.micro to var.ec2_instance_type

same as do for ami_id and volume_size

let’s change volume_size using variable

now value is changed after above

now output.tf

🚀 Here we want to install an EC2 instance and also install Nginx

now it is working.

🔹Dynamic configurations

Dynamic configuration means:

✅ Making your Terraform code adapt automatically to changing variables, environments, and conditions.
✅ Allowing flexibility (code reuse, scaling infra easily).
✅ Using variables, conditionals, count, for_each, and dynamic blocks to decide:

  • What resources to create (and how many).

  • Which values to assign dynamically at runtime.


Why is it important?

  • You avoid hardcoding repetitive code.

  • Infra scales automatically with changes.

  • Easier environment management (dev, stage, prod).

1️⃣Conditional Expressions

Used to set values based on conditions.

Syntax:

condition ? true_value : false_value

Example: Enable public IP only if in production

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  associate_public_ip_address = var.environment == "prod" ? true : false
}

Here,

  • If var.environment is "prod", it attaches a public IP.

  • Else, it does not.

default volume size is 10

2️⃣ Meta argument OR Dynamic Blocks (for_each,count)

1️⃣ count

✅ Used to create multiple identical resources dynamically.

Example:

resource "aws_instance" "web" {
  count = 3
  ami = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

It will create 3 EC2 instances.

here also we want to change on outputs.tf . because we have multiple instance not a single instance.

but here all instance name is same.

2️⃣ for_each

✅ Used to create multiple resources from a map or set, allowing individual indexing and mapping.

Example:

resource "aws_instance" "web" {
  for_each = tomap({
    web1 = "t2.micro", 
    web2 = "t2.medium", 
    web3 = "t2.large"
  })
  ami = "ami-0c55b159cbfafe1f0"
  instance_type = each.value
  tags = {
    Name = each.key
  }
}

It will create 3 instances with names web1, web2, web3.

but it not support on outputs.tf. so, comment it

and then write this on outputs.tf

3️⃣depends_on

✅ Forces explicit dependency between resources when Terraform cannot detect it automatically.

🔹Terraform state management and Backends

🚀Role of state in infrastructure management

1️⃣ What is Terraform State?

✅ Terraform state is a file (terraform.tfstate) that keeps track of your real infrastructure on the cloud and maps it to your Terraform configuration.

It contains:

  • Resource metadata (IDs, attributes).

  • Dependencies between resources.

  • Output values.

  • Resource instances created with count and for_each.


2️⃣ Why is State Important?

Terraform uses state to:

✅ Map resources: Knows which resources it manages and their current properties on the cloud.
✅ Determine changes: Compares your configuration with state to create an execution plan (terraform plan).
✅ Track dependencies: Understands resource relationships to manage correct creation, update, or deletion order.
✅ Improve performance: Stores information locally, avoiding repeated API calls to fetch details during plan/apply.
✅ Support collaboration: When using remote state, teams can work together safely.


3️⃣ Example Scenario:

You create:

resource "aws_instance" "web" {
  ami = "ami-123456"
  instance_type = "t2.micro"
}
  • On terraform apply, Terraform creates an EC2 instance and saves its instance ID, type, and other attributes into terraform.tfstate.

  • Next time, if you change instance_type to t2.small, Terraform:

    • Checks the state file to know an instance already exists.

    • Determines that only the type needs an update, not a new instance.

    • Plans and applies only the necessary change.


4️⃣ State File Location

By default:

  • Saved locally in the working directory as terraform.tfstate.

  • A backup is stored as terraform.tfstate.backup.

check bhagya-automate-micro state in terraform.tfstate

it is a running

now we stop it in aws.

and Now according to aws bhagya-automate-micro is a stop. but according to state file it is a running.so use terraform refresh

so now instance state is stopped.

✅ Common terraform state subcommands:


1️⃣ list

Lists all resources tracked in the state.

Usage:

terraform state list

Example Output:


2️⃣ show

Displays detailed attributes of a single resource in the state.

Usage:

terraform state show <resource_address>

Example:


3️⃣ rm

Removes a resource from the state without destroying the real infrastructure.

Usage:

terraform state rm <resource_address>

Example:

After this, Terraform will stop managing the resource.

but it is still in aws. no, if you want to back this key .

so do below step

copy this id

sorry but above is not working. so do below commands.

now we want to import manual instance from aws to terraform

for create another import another instance write like this

copy instance id which is we want to import.


🚀Secure state management Best practices

What is Secure State Management?

The terraform.tfstate file stores your infrastructure's real state (resources, attributes, metadata).
It often contains sensitive data:

  • Resource IDs

  • IP addresses

  • Secrets (plain-text passwords, private keys, etc.)

Secure state management means protecting this state file from unauthorized access, corruption, and data loss.

Why is it important?

  • Prevent leaks of sensitive data (e.g., DB passwords, cloud credentials).

  • Avoid state corruption causing infrastructure drift or downtime.

  • Enable safe team collaboration without conflicting updates.

🚩 Best Practices for Secure State Management

1️⃣ Use Remote State Storage

✅ Do not store state files locally in production or team environments.
✅ Use remote backends like:

  • AWS S3

  • Azure Blob Storage

  • Google Cloud Storage

  • Terraform Cloud/Enterprise

This ensures:
✅ Centralized, consistent state storage
✅ Easy collaboration across teams
✅ Offsite backups


2️⃣ Enable State Locking

When multiple people or CI/CD pipelines work on the same state:
✅ Enable state locking to prevent simultaneous apply operations.

How:

  • Use DynamoDB with S3 backend for AWS.

  • Terraform Cloud handles locking automatically.

This prevents race conditions and corruption.

🚀Remote state Backends practical

1️⃣DynamoDB with S3 backend for AWS.

Add a new folder for remote infrastructure

create above files

go to here:- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket

for creating s3 bucket

now take a aws provider

now for a dynamodb go to here:- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table

show on AWS how work

How to restore a terraform state from backup ?

To restore a terraform state from backup, rename the backup file (e.g., terraform.tfstate.backup) to the standard file name(terraform.tfstate), and then run terraform init

lets first remove terrafor.tfstate file

then rename backup file

now after use terraform init.

Done.

change it

now you will delete terraform.tfstate and his backup files in vscode

here we deleted terraform.tfstate and his backup file. sill it is working. it is used when one person then it is generated lock_id . then it is locked for other people

🔹Terraform Workspaces & Environment management

🚀 What are Workspaces in Terraform?

Terraform Workspaces allow you to manage multiple state files within the same Terraform configuration.

Default behavior:

  • By default, Terraform uses a single workspace called default.

  • This workspace has one state file storing resource mappings.


Why are Workspaces Useful?

They help you:
✅ Manage multiple environments (dev, test, prod) without copying configurations.
✅ Keep separate states for each environment within the same code.
✅ Avoid resource conflicts across environments.

“In Terraform, a workspace is similar to a branch in GitHub, as both allow you to manage different versions or environments separately within the same configuration or codebase.”


How it works practically:

  • Each workspace has its own state:

    • terraform.tfstate for default

    • terraform.tfstate.d/<workspace_name>/terraform.tfstate for other workspaces

  • Resources created in one workspace do not affect resources in another workspace.


Basic Commands

1️⃣ List existing workspaces:

terraform workspace list

2️⃣ Create a new workspace:

terraform workspace new dev

3️⃣ Switch to another workspace:

terraform workspace select dev

4️⃣ Show the current workspace:

terraform workspace show

Example Use Case:

You have the same configuration:

  • In the dev workspace: resources are created with smaller instances.

  • In the prod workspace: resources are created with larger instances.

Both use the same Terraform code but maintain isolated state and resources.

2
Subscribe to my newsletter

Read articles from Bhagya-patel directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Bhagya-patel
Bhagya-patel