# Automating AWS Infrastructure Using Terraform: VPC, EC2, S3, and Load Balancer Setup

As part of my DevOps learning journey, I recently worked on a project to automate a basic but complete AWS infrastructure using **Terraform**. This was a hands-on experience where I provisioned and configured networking, compute, storage, and load balancing resources using Infrastructure as Code (IaC). Here's a breakdown of what I built, how it works, the challenges I faced, and the lessons learned.

---

## Project Overview

The goal was to provision the following AWS components using Terraform:

* A **VPC** with two **public subnets** in different Availability Zones
    
* An **Internet Gateway** and **Route Table**
    
* A **Security Group** with HTTP and SSH access
    
* Two **EC2 instances** with user-data scripts
    
* An **S3 bucket** with full access granted to EC2 via IAM Role
    
* An **Application Load Balancer (ALB)** with target groups and listeners
    

---

## Infrastructure Details

### 1\. **VPC and Subnets**

I created a custom VPC and two subnets in different AZs:

```plaintext
resource "aws_vpc" "myvpc" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "sub1" {
  vpc_id                  = aws_vpc.myvpc.id
  cidr_block              = "10.0.0.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true
}

resource "aws_subnet" "sub2" {
  vpc_id                  = aws_vpc.myvpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1b"
  map_public_ip_on_launch = true
}
```

### 2\. **Internet Gateway and Route Table**

To enable internet access:

```plaintext
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.myvpc.id
}

resource "aws_route_table" "RT" {
  vpc_id = aws_vpc.myvpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
}

resource "aws_route_table_association" "rta1" {
  subnet_id      = aws_subnet.sub1.id
  route_table_id = aws_route_table.RT.id
}

resource "aws_route_table_association" "rta2" {
  subnet_id      = aws_subnet.sub2.id
  route_table_id = aws_route_table.RT.id
}
```

### 3\. **Security Group**

Allowing inbound traffic:

```plaintext
resource "aws_security_group" "webSg" {
  name   = "web"
  vpc_id = aws_vpc.myvpc.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    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"]
  }
}
```

### 4\. **IAM Role for S3 Access**

Attaching an S3 access role to EC2:

```plaintext
resource "aws_iam_role" "ec2_role" {
  name = "ec2_s3_role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [{
      Effect = "Allow",
      Principal = { Service = "ec2.amazonaws.com" },
      Action = "sts:AssumeRole"
    }]
  })
}

resource "aws_iam_role_policy_attachment" "ec2_role_attachment" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
  role       = aws_iam_role.ec2_role.name
}

resource "aws_iam_instance_profile" "ec2_profile" {
  name = "ec2_s3_profile"
  role = aws_iam_role.ec2_role.name
}
```

### 5\. **EC2 Instances**

Launching two EC2 instances in each subnet:

```plaintext
resource "aws_instance" "webservers1" {
  ami                    = "ami-020cba7c55df1f615"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.sub1.id
  vpc_security_group_ids = [aws_security_group.webSg.id]
  user_data              = base64encode(file("userdata.sh"))
  iam_instance_profile   = aws_iam_instance_profile.ec2_profile.name
}

resource "aws_instance" "webservers2" {
  ami                    = "ami-020cba7c55df1f615"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.sub2.id
  vpc_security_group_ids = [aws_security_group.webSg.id]
  user_data              = base64encode(file("userdata1.sh"))
  iam_instance_profile   = aws_iam_instance_profile.ec2_profile.name
}
```

### 6\. **Application Load Balancer**

Distributing traffic evenly:

```plaintext
resource "aws_lb" "myalb" {
  name               = "myalb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.webSg.id]
  subnets            = [aws_subnet.sub1.id, aws_subnet.sub2.id]
}

resource "aws_lb_target_group" "tg" {
  name     = "myTG"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.myvpc.id

  health_check {
    path = "/"
    port = "traffic-port"
  }
}

resource "aws_lb_target_group_attachment" "attach1" {
  target_group_arn = aws_lb_target_group.tg.arn
  target_id        = aws_instance.webservers1.id
  port             = 80
}

resource "aws_lb_target_group_attachment" "attach2" {
  target_group_arn = aws_lb_target_group.tg.arn
  target_id        = aws_instance.webservers2.id
  port             = 80
}

resource "aws_lb_listener" "listener" {
  load_balancer_arn = aws_lb.myalb.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.tg.arn
  }
}
```

---

## Challenges I Faced

* **IAM Role Confusion**: It took me time to properly link the IAM role to EC2 with the correct trust relationship and instance profile. This blog helped: [Mahira Technology on IAM + EC2 + S3](https://mahira-technology.medium.com/how-to-create-an-iam-role-with-full-s3-permission-and-assign-to-ec2-using-terraform-and-access-s3-b9eba4b30dcd)
    
* **ALB Configuration**: Understanding the flow between ALB, listener, target groups, and EC2 was tricky at first. I referred to the [Terraform AWS Load Balancer Docs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb)
    

---

## Key Takeaways

* Terraform makes AWS resource provisioning scalable and repeatable
    
* Load balancers distribute traffic and improve availability
    
* IAM roles are critical for secure access to other AWS services like S3
    
* Having a strong understanding of AWS networking (VPCs, Subnets, Routing) is essential
    

---

## Final Thoughts

This project was an incredible learning experience and helped me gain confidence in working with Terraform and AWS. It was a practical way to understand how real infrastructure is set up in production.

If you're also exploring DevOps, Cloud, or Infrastructure as Code, I highly recommend trying something similar. Want help setting up your own? Feel free to reach out!

---
