Terraform

🔹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️⃣ Initializeterraform init
initializes your working directory.
3️⃣ Planterraform plan
shows what will be created, changed, or destroyed.
4️⃣ Applyterraform apply
actually makes the changes on your cloud provider.
5️⃣ Destroyterraform destroy
will clean up all resources when you no longer need them.
🔹 Terraform vs Ansible
Aspect | Terraform | Ansible |
Purpose | Infrastructure Provisioning | Configuration Management (and some provisioning) |
Type | Declarative IaC | Procedural (imperative) and declarative |
Primary Use | Create, modify, destroy infrastructure (VMs, networks, databases) | Configure software and environments on provisioned servers |
Language | HCL (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️⃣ Initializeterraform init
initializes your working directory.
3️⃣ Planterraform plan
shows what will be created, changed, or destroyed.
4️⃣ Applyterraform apply
actually makes the changes on your cloud provider.
5️⃣ Destroyterraform 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
andfor_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 intoterraform.tfstate
.Next time, if you change
instance_type
tot2.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
fordefault
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.
Subscribe to my newsletter
Read articles from Bhagya-patel directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
