<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Automating AWS Infrastructure]]></title><description><![CDATA[Automating AWS Infrastructure]]></description><link>https://blog.saminder.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 12 May 2026 13:20:02 GMT</lastBuildDate><atom:link href="https://blog.saminder.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Automating AWS Infrastructure Using Terraform: VPC, EC2, S3, and Load Balancer Setup]]></title><description><![CDATA[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 balanc...]]></description><link>https://blog.saminder.com/automating-aws-infrastructure-using-terraform-vpc-ec2-s3-and-load-balancer-setup</link><guid isPermaLink="true">https://blog.saminder.com/automating-aws-infrastructure-using-terraform-vpc-ec2-s3-and-load-balancer-setup</guid><category><![CDATA[Devops]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Terraform]]></category><category><![CDATA[infrastructure]]></category><category><![CDATA[Infrastructure as code]]></category><dc:creator><![CDATA[Saminder Singh]]></dc:creator><pubDate>Wed, 09 Jul 2025 07:18:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752045168321/0629de18-df00-46f4-8a05-9089eef60225.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As part of my DevOps learning journey, I recently worked on a project to automate a basic but complete AWS infrastructure using <strong>Terraform</strong>. 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.</p>
<hr />
<h2 id="heading-project-overview">Project Overview</h2>
<p>The goal was to provision the following AWS components using Terraform:</p>
<ul>
<li><p>A <strong>VPC</strong> with two <strong>public subnets</strong> in different Availability Zones</p>
</li>
<li><p>An <strong>Internet Gateway</strong> and <strong>Route Table</strong></p>
</li>
<li><p>A <strong>Security Group</strong> with HTTP and SSH access</p>
</li>
<li><p>Two <strong>EC2 instances</strong> with user-data scripts</p>
</li>
<li><p>An <strong>S3 bucket</strong> with full access granted to EC2 via IAM Role</p>
</li>
<li><p>An <strong>Application Load Balancer (ALB)</strong> with target groups and listeners</p>
</li>
</ul>
<hr />
<h2 id="heading-infrastructure-details">Infrastructure Details</h2>
<h3 id="heading-1-vpc-and-subnets">1. <strong>VPC and Subnets</strong></h3>
<p>I created a custom VPC and two subnets in different AZs:</p>
<pre><code class="lang-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
}
</code></pre>
<h3 id="heading-2-internet-gateway-and-route-table">2. <strong>Internet Gateway and Route Table</strong></h3>
<p>To enable internet access:</p>
<pre><code class="lang-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
}
</code></pre>
<h3 id="heading-3-security-group">3. <strong>Security Group</strong></h3>
<p>Allowing inbound traffic:</p>
<pre><code class="lang-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"]
  }
}
</code></pre>
<h3 id="heading-4-iam-role-for-s3-access">4. <strong>IAM Role for S3 Access</strong></h3>
<p>Attaching an S3 access role to EC2:</p>
<pre><code class="lang-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
}
</code></pre>
<h3 id="heading-5-ec2-instances">5. <strong>EC2 Instances</strong></h3>
<p>Launching two EC2 instances in each subnet:</p>
<pre><code class="lang-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
}
</code></pre>
<h3 id="heading-6-application-load-balancer">6. <strong>Application Load Balancer</strong></h3>
<p>Distributing traffic evenly:</p>
<pre><code class="lang-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
  }
}
</code></pre>
<hr />
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<ul>
<li><p><strong>IAM Role Confusion</strong>: It took me time to properly link the IAM role to EC2 with the correct trust relationship and instance profile. This blog helped: <a target="_blank" href="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">Mahira Technology on IAM + EC2 + S3</a></p>
</li>
<li><p><strong>ALB Configuration</strong>: Understanding the flow between ALB, listener, target groups, and EC2 was tricky at first. I referred to the <a target="_blank" href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb">Terraform AWS Load Balancer Docs</a></p>
</li>
</ul>
<hr />
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ul>
<li><p>Terraform makes AWS resource provisioning scalable and repeatable</p>
</li>
<li><p>Load balancers distribute traffic and improve availability</p>
</li>
<li><p>IAM roles are critical for secure access to other AWS services like S3</p>
</li>
<li><p>Having a strong understanding of AWS networking (VPCs, Subnets, Routing) is essential</p>
</li>
</ul>
<hr />
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>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.</p>
<p>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!</p>
<hr />
]]></content:encoded></item></channel></rss>