Terraform Tutorial — Resources Practice Exercises

2 minute read

Practice creating, configuring, and managing Terraform resources.


Exercise 1: Read a Resource Block

Task: Given this resource block, identify: the resource type, the local name, two required arguments, and how you would reference the instance’s public IP elsewhere.

resource "aws_instance" "app_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.small"
  key_name      = "my-key"

  tags = {
    Name = "app-server"
  }
}
Answer
  • Resource type: aws_instance
  • Local name: app_server
  • Required arguments: ami and instance_type
  • Reference public IP: aws_instance.app_server.public_ip

Exercise 2: Dependencies

Task: Write a VPC and a subnet where the subnet depends on the VPC. Use an implicit dependency (reference).

Answer
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "main-vpc"
  }
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"

  tags = {
    Name = "public-subnet"
  }
}

The reference aws_vpc.main.id creates an implicit dependency — Terraform creates the VPC before the subnet.


Exercise 3: Lifecycle

Task: Write a resource for an RDS database that cannot be accidentally destroyed and creates a new instance before destroying the old one during updates.

Answer
resource "aws_db_instance" "main" {
  allocated_storage = 20
  engine            = "postgres"
  engine_version    = "15.4"
  instance_class    = "db.t3.micro"
  db_name           = "mydb"
  username          = "admin"
  password          = var.db_password

  lifecycle {
    prevent_destroy       = true
    create_before_destroy = true
  }
}

Exercise 4: count vs for_each

Task: Create three S3 buckets using for_each with the names “logs”, “assets”, and “backups”. Each bucket should be named myproject-<name>.

Answer
resource "aws_s3_bucket" "buckets" {
  for_each = toset(["logs", "assets", "backups"])

  bucket = "myproject-${each.value}"

  tags = {
    Name      = each.value
    ManagedBy = "terraform"
  }
}

Exercise 5: Full Resource Configuration

Task: Write a complete Terraform configuration that creates an EC2 instance with a security group allowing HTTP (port 80) inbound traffic. The security group should reference a VPC.

Answer
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Allow HTTP inbound traffic"
  vpc_id      = aws_vpc.main.id

  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                    = "ami-0c55b159cbfafe1f0"
  instance_type          = "t3.micro"
  vpc_security_group_ids = [aws_security_group.web.id]

  tags = {
    Name = "web-server"
  }
}

Chapter Summary

In this chapter, you learned:

  • The resource block anatomy: type, local name, arguments, and computed attributes
  • How to create an S3 bucket step-by-step with init, plan, apply, and destroy
  • Implicit dependencies through references and explicit dependencies with depends_on
  • The lifecycle block: create_before_destroy, prevent_destroy, ignore_changes
  • Meta-arguments: count, for_each, depends_on, provider, lifecycle

Next up: Variables — making your configuration reusable.


← Meta-Arguments Overview Variables →