Ravindra BagaleCourses & study guides मराठी

Chapter 33: Terraform Providers Resources Variables Outputs Locals and Data Sources

33.2 Resources — the things Terraform creates

Story. An Infosys client asked for an S3 bucket for build logs, and the junior engineer created it in the console. Three months later nobody knew who owned it or whether it was safe to delete. A resource block is the fix: it is a typed, named object that Terraform creates, tracks in state, updates and deletes. Other resources refer to it by type.name.attribute, which is how Terraform learns the order to build things.

resource type + name attributes reference type.name.attr plan create
A resource has a type and a local name; others refer to it as type.name.attribute.
resource "aws_s3_bucket" "logs" {
  bucket = "badge-build-logs-<your-account-id>"
}

resource "aws_s3_bucket_versioning" "logs" {
  bucket = aws_s3_bucket.logs.id
  versioning_configuration {
    status = "Enabled"
  }
}

What each line does

  • resource "aws_s3_bucket" "logs" { — Declares an S3 bucket; aws_s3_bucket is the type and logs is the name inside this code.
  • bucket = "badge-build-logs-<your-account-id>" — The globally unique bucket name; replace the placeholder with your own suffix.
  • resource "aws_s3_bucket_versioning" "logs" { — A separate resource that controls versioning for a bucket.
  • bucket = aws_s3_bucket.logs.id — Refers to the first bucket, which also tells Terraform to create the bucket first.
  • status = "Enabled" — Turns on versioning so overwritten objects can be recovered.

When it is green.

  # aws_s3_bucket.logs will be created
  + resource "aws_s3_bucket" "logs" { + bucket = "badge-build-logs-..." }
  # aws_s3_bucket_versioning.logs will be created
  + resource "aws_s3_bucket_versioning" "logs" { ... }

Plan: 2 to add, 0 to change, 0 to destroy.

When it is red.

Error: creating S3 Bucket (badge-build-logs): BucketAlreadyExists:
The requested bucket name is not available.

Fix. Bucket names are global across all AWS accounts. Add your account id or a random suffix to the name and plan again.

What: every term in plain English

  • resource block — resource "TYPE" "NAME" { ... }. One real object Terraform creates and manages.
  • type — What kind of object, such as aws_s3_bucket. It starts with the provider name.
  • name — Your label inside the code, such as logs. Not the AWS name.
  • argument — A setting you write, such as bucket = "...".
  • attribute — A value you can read after create, such as .arn or .id.
  • address — TYPE.NAME, such as aws_s3_bucket.logs. Used in state and plans.
  • reference — Using one resource value in another, such as aws_s3_bucket.logs.id.

Example 1: A bucket for build logs

An Infosys team made a log bucket in the console and nobody knew who owned it. In code, the owner, tags and settings are in Git.

resource "aws_s3_bucket" "build_logs" {
  bucket = "infy-build-logs-1234"
  tags = {
    Owner = "ci-team"
  }
}

resource "aws_s3_bucket_versioning" "build_logs" {
  bucket = aws_s3_bucket.build_logs.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_public_access_block" "build_logs" {
  bucket                  = aws_s3_bucket.build_logs.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}
terraform apply -auto-approve
terraform state list

Output

aws_s3_bucket.build_logs: Creation complete after 2s [id=infy-build-logs-1234]
aws_s3_bucket_versioning.build_logs: Creation complete after 1s
aws_s3_bucket_public_access_block.build_logs: Creation complete after 1s
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

aws_s3_bucket.build_logs
aws_s3_bucket_public_access_block.build_logs
aws_s3_bucket_versioning.build_logs

What it shows: The reference aws_s3_bucket.build_logs.id makes Terraform create the bucket first.

Example 2: EC2 server that uses a security group

A Zomato-style team needs a web server. The server reads the group id, so order is automatic.

data "aws_ami" "al2023" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["al2023-ami-2023.*-x86_64"]
  }
}

resource "aws_security_group" "web" {
  name = "demo-web-sg"
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web" {
  ami                    = data.aws_ami.al2023.id
  instance_type          = "t3.micro"
  vpc_security_group_ids = [aws_security_group.web.id]
  tags = {
    Name = "demo-web"
  }
}
terraform apply -auto-approve
terraform state show aws_instance.web | grep -E "public_ip |instance_type|id  "

Output

aws_security_group.web: Creation complete after 2s [id=sg-0abc1234def567890]
aws_instance.web: Creation complete after 13s [id=i-0123456789abcdef0]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

    id                     = "i-0123456789abcdef0"
    instance_type          = "t3.micro"
    public_ip              = "13.233.10.20"

What it shows: The IP is a sample. state show lists every attribute you can reference.

Example 3: Change in place vs replace

Know which edits are safe. A tag change is in place. An AMI change replaces the server.

# edit 1: change tag Name to demo-web-1
terraform plan | grep -E "~|-/\+|Plan:"
# edit 2: change ami to another id
terraform plan | grep -E "forces replacement|Plan:"

Output

  ~ resource "aws_instance" "web" {
      ~ tags = { ~ "Name" = "demo-web" -> "demo-web-1" }
Plan: 0 to add, 1 to change, 0 to destroy.

      ~ ami = "ami-0aaa..." -> "ami-0bbb..." # forces replacement
Plan: 1 to add, 0 to change, 1 to destroy.

What it shows: Read every plan for -/+ and forces replacement before you apply in prod.

Example 4: Find the right arguments in the docs

Freshers at TCS often guess argument names. The provider docs list them, and validate catches typos.

  1. Open registry.terraform.io, search aws_s3_bucket_lifecycle_configuration.
  2. Copy the Example Usage.
  3. Run validate.
resource "aws_s3_bucket_lifecycle_configuration" "build_logs" {
  bucket = aws_s3_bucket.build_logs.id
  rule {
    id     = "expire-old-logs"
    status = "Enabled"
    filter {}
    expiration {
      days = 30
    }
  }
}
terraform validate
terraform apply -auto-approve

Output

Success! The configuration is valid.
aws_s3_bucket_lifecycle_configuration.build_logs: Creation complete after 31s
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

What it shows: Logs older than 30 days are deleted. This saves money with no script.

Command cheat sheet

Command What it does When to use it
terraform validate Catch wrong arguments Before every plan
terraform state list List resource addresses After apply
terraform state show ADDR Show all attributes Finding values to reference
terraform plan See add, change, replace Every edit
terraform apply -​replace=​ADDR Force a rebuild Broken server
terraform destroy -​target=​ADDR Delete one thing Emergency only

Verify: did it work?

  1. Resource exists

    terraform state list | grep build_logs
    

    Output

    aws_s3_bucket.build_logs
    
  2. Versioning on

    aws s3api get-bucket-versioning --bucket infy-build-logs-1234 --query Status --output text
    

    Output

    Enabled
    
  3. Code matches

    terraform plan
    

    Output

    No changes. Your infrastructure matches the configuration.
    

When it is red 1

Error: Unsupported argument
  on main.tf line 3, in resource "aws_s3_bucket" "build_logs":
   3:   versioning = true
An argument named "versioning" is not expected here.

Cause. In AWS provider 5, versioning is its own resource.

Fix, step by step

  1. Remove the line.
  2. Add aws_s3_bucket_versioning.

When it is red 2

Error: creating S3 Bucket (infy-build-logs-1234): BucketAlreadyExists

Cause. The name is taken globally.

Fix, step by step

  1. Add a unique suffix such as your account id.

When it is red 3

Error: Reference to undeclared resource
  on main.tf line 12: bucket = aws_s3_bucket.logs.id

Cause. The name in the reference does not match the block label.

Fix, step by step

  1. Use aws_s3_bucket.build_logs.id.

Cleanup

terraform destroy -auto-approve

Ravindra Bagale's Tip

Before apply, search the plan for -/+ and forces replacement. That one habit saves servers and databases.

Practice tasks

Easy Safe bucket

Why: Good defaults.

What to do: Make a bucket with versioning and public access block.

How:
  1. Three resources.

Check: 3 added.

Medium Server with group

Why: References.

What to do: Make a group and a server that uses it.

How:
  1. Use .id.

Check: Group created first.

Medium Spot replace

Why: Read plans.

What to do: Change a tag, then an AMI, and compare plans.

How:
  1. grep forces replacement.

Check: You can tell which is which.

Hard Lifecycle rule

Why: Save money.

What to do: Expire objects after 30 days.

How:
  1. Copy docs example, validate.

Check: Rule shows in console.

Easy Say it in two lines

Why: If you can say it simply, you understand it.

What to do: Write two short lines about this lesson for a fresher.

How:
  1. Write the problem it solves.
  2. Write the one command or file you use.
  3. Read it aloud.

Check: A fresher understands it without a question.

Easy Start a safe lab folder

Why: Practice needs a throwaway place.

What to do: Make a new folder with versions.tf and a random_pet resource, so no AWS cost.

How:
  1. mkdir tf-lab and cd into it.
  2. Add the hashicorp/random provider and one random_pet.
  3. Run terraform init and terraform apply.

Check: Apply complete! with 1 added.

Medium Break it on purpose

Why: You must know the red output by face.

What to do: Cause one error from the red part of this lesson and fix it.

How:
  1. Follow one red section.
  2. Copy the exact message to your notes.
  3. Write the fix in one line.

Check: You fixed it without searching the web.

Medium Run it twice

Why: A second run must be quiet.

What to do: Run the same plan two times with no edits.

How:
  1. Run terraform plan.
  2. Run it again.
  3. Explain any change it still shows.

Check: The second plan says No changes, or you can explain each line.

Medium Write a runbook page

Why: At 2 a.m. nobody remembers flags.

What to do: Write a one-page runbook for this lesson.

How:
  1. Title, when to use, exact commands, how to check, how to undo.

Check: A teammate can follow it alone.

Medium Run it from a pipeline

Why: Real teams run Terraform from CI, not from laptops.

What to do: Run the main command of this lesson inside a GitHub Actions or Jenkins job.

How:
  1. Add a job with hashicorp/setup-terraform or a Terraform Docker image.
  2. Give it AWS access through an IAM role, never a key in the file.
  3. Run init, then the command from this lesson.

Check: The job log shows the same output you saw on your laptop.

Medium Check the cost

Why: Labs left running cost real money.

What to do: Find what this lesson would cost per day if you forgot to destroy it.

How:
  1. Open the AWS Pricing Calculator.
  2. Add each resource from your plan.
  3. Write the daily cost in your notes.

Check: You know the daily cost and you ran terraform destroy.

Hard Draw the flow top to bottom

Why: A drawing shows the order of work.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at your code, go through plan and state, end at AWS.
  2. Mark where each command reads or writes.

Check: Each box matches a real step you ran.

Hard Explain it like an interview

Why: Interviewers want real stories.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the command, and one error you hit.

Check: Your answer has a real command and a real error message.

Homework: try at home

Try at home

Pick three resources from the AWS provider docs. For each, write two arguments and two attributes you would use.

Recap

  • A resource is one real object: TYPE.NAME.
  • Arguments go in, attributes come out.
  • References set the order for you.
  • Watch plans for forces replacement.
  • Use the docs and validate, never guess.

FAQ

Is the resource name the AWS name?

No. The label is for code. The AWS name is an argument like bucket.

Can I rename the label?

Yes, with a moved block, or the plan will destroy and create.

Why is versioning a separate resource?

AWS provider 5 split bucket settings into their own resources.

What is .id?

The main id of the object, such as the bucket name or i-....

How do I see all attributes?

terraform state show ADDRESS.

Interview questions

  1. Parts of a resource block?

    Type, local name, and arguments in the body.

  2. Argument vs attribute?

    Arguments are what you set. Attributes are what you can read after creation.

  3. How does Terraform know the order?

    From references between resources; it builds a graph.

  4. What does forces replacement mean?

    That argument cannot change in place; the object will be destroyed and created again.

  5. How do you rebuild one broken resource?

    terraform apply -replace=ADDRESS.

Quick quiz

Q1. Address form?

TYPE.NAME

Q2. Command to list all attributes?

terraform state show

Q3. Versioning in AWS provider 5?

A separate resource.

Q4. Symbol for replace in plan?

-/+

Q5. Command to check arguments?

terraform validate

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards