Youtube Video link: https://youtu.be/BWhQOoS3PeI
Github repo: https://github.com/rashiddaha/terraform-course
In Previous ( Part 01 , Part 02 , Part 03 ) We have discussed Introduction to Terraform, Terraform, and aws cli Setup.In this Part 04 article, we will be discussing the fourth part of the Terraform series, where we will be creating a VPC with a Subnet, Security Group, and EC2 instance. We will create an Amazon Virtual Private Cloud (VPC) with a Subnet, Internet Gateway, and Custom Route Table using Terraform. We will then create an Elastic Network Interface (ENI) and associate an Elastic IP (EIP) address with it. We will also create a Security Group to allow ports 22, 80, and 443. Finally, we will create an EC2 instance and install Apache2 on it.
By the end of this article, you will have a solid understanding of creating a VPC with Subnet, Security Group, and EC2 instance using Terraform. Letâs begin by discussing the project outline.
Project Outline
The project outline consists of the following steps:
- Create VPC
2. Create Internet Gateway
3. Create Custom Route Table
4. Create Subnet
5. Associate Subnet with Route Table
6. Create Security Group to allow ports: 22, 80, 443
7. Assign ENI with IP
8. Assign Elastic IP to ENI
9. Create IAM Role to access S3
10. Create Linux Server and Install/Enable Apache2
10. Enable VCP Endpoint
11. Setting up the Environment
Before we start creating the infrastructure, we need to set up the environment. We will be using the AWS provider for Terraform to create the infrastructure in AWS. The first step is to create a directory and initialize it with Terraform:
mkdir terraform-vpc
cd terraform-vpc
terraform init
Next, we need to create a file with the .tf extension that will contain the Terraform code. We will name it main.tf.
touch main.tf
Now, open the main.tf file in your favorite text editor and paste the following code:
// Configure the AWS Provider
provider "aws" {
region = "us-east-1"
}
This code configures the AWS provider for Terraform and sets the region to us-east-1.
1. Creating a VPC
Now, we can move on to creating a VPC. We will use the aws_vpc resource to create the VPC.
# 1) Create VPC
resource "aws_vpc" "A" {
cidr_block = "10.0.0.0/16"
tags = {
name = "Codewithmuh"
}
}
Here, we create a VPC with the CIDR block 10.0.0.0/16. We also add a tag with the name Codewithmuh to identify the VPC.
2. Creating an Internet Gateway
Next, we need to create an Internet Gateway to allow our VPC to communicate with the Internet. We will use the aws_internet_gateway resource for this.
# 2) Create Internet Gateway
resource "aws_internet_gateway" "GW_Codewithmuh" {
vpc_id = aws_vpc.A.id
tags = {
Name = "IG_Codewithmuh"
}
}
Here, we create an Internet Gateway and associate it with the VPC we created earlier. We also add a tag to identify the Internet Gateway.
3.Creating a Custom Route Table
After creating the VPC and the Internet Gateway, we can create a custom route table to specify how traffic should be routed between the VPC and the internet. In this case, we want to route all internet-bound traffic through the Internet Gateway we just created.
To create a custom route table in Terraform, we use the aws_route_table resource. We specify the VPC ID using the vpc_id attribute and then define a default route to the internet gateway using the route block:
# 3) Create Route Table
resource "aws_route_table" "RT_Codewithmuh" {
vpc_id = aws_vpc.A.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.GW_Codewithmuh.id
}
route {
ipv6_cidr_block = "::/0"
gateway_id = aws_internet_gateway.GW_Codewithmuh.id
}
tags = {
Name = "RT_Codewithmuh"
}
}
Here, we create a aws_route_table resource named "RT_Codewithmuh". We set the vpc_id attribute to the ID of the VPC we created earlier using aws_vpc.A.id.
Next, we define a default route to the internet gateway using the route block. We specify a CIDR block of 0.0.0.0/0, which matches all IP addresses, and set the gateway_id attribute to the ID of the internet gateway we created earlier using aws_internet_gateway.GW_Codewithmuh.id.
Finally, we add a tags block to the resource to give it a descriptive name.
4. Creating a Subnet
Now that we have a VPC and a route table, we can create a subnet for our resources. In this case, we want to create a subnet in the us-east-1a availability zone with a CIDR block of 10.0.0.0/24.
To create a subnet in Terraform, we use the aws_subnet resource. We specify the VPC ID using the vpc_id attribute, the CIDR block using the cidr_block attribute, and the availability zone using the availability_zone attribute:
# 4) Create Subnet
resource "aws_subnet" "Subnet_Codewithmuh" {
vpc_id = aws_vpc.A.id
cidr_block = "10.0.0.0/24"
availability_zone = "us-east-1a"
depends_on = [aws_internet_gateway.GW_Codewithmuh]
tags = {
Name = "Subnet_Codewithmuh"
}
}
Here, we create a aws_subnet resource named "Subnet_Codewithmuh". We set the vpc_id attribute to the ID of the VPC we created earlier using aws_vpc.A.id, the cidr_block attribute to 10.0.0.0/24, and the availability_zone attribute to "us-east-1a". We also set the depends_on attribute to the internet gateway resource to ensure that the subnet is created after the internet gateway.
Finally, we add a tags block to the resource to give it a descriptive name.
5. Associate Subnet with Route Table
To associate the Subnet with the Route Table, we will use the âaws_route_table_associationâ resource. In the code, we have already created the Subnet and the Route Table. We will use their IDs to create the association. Add the following code to your project:
# 5) Associate Subnet with Route Table
resource "aws_route_table_association" "RT_to_Subnet" {
subnet_id = aws_subnet.Subnet_Codewithmuh.id
route_table_id = aws_route_table.RT_Codewithmuh.id
}
We have created a new resource called âaws_route_table_associationâ and assigned the Subnet ID to âsubnet_idâ and Route Table ID to âroute_table_idâ. This will create an association between the Subnet and the Route Table.
6. Create a Security Group to allow ports: 22, 80, 443
# 6) Create Security Group to allow ports: 22, 80, 443
resource "aws_security_group" "SG_Codewithmuh" {
name = "SG_Codewithmuh"
description = "Allow SSH, HTTP, HTTPS inbound traffic"
vpc_id = aws_vpc.A.id
ingress {
description = "HTTPS from VPC"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP from VPC"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH from VPC"
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"]
}
tags = {
Name = "SG_Codewithmuh"
}
}
Here, we are using the aws_security_group resource to create a security group named SG_Codewithmuh. We are providing a name prefix for the security group, along with the VPC ID of the VPC we created earlier (aws_vpc.A.id).
We are also defining ingress rules to allow traffic on ports 22 (SSH) and 80 (HTTP) from any IP address (0.0.0.0/0), and egress rules to allow all outbound traffic.
Finally, we are adding a tag to the security group for easy identification.
7. Assign ENI with IP
# 7) Assign ENI with IP
resource "aws_network_interface" "ENI_A" {
subnet_id = aws_subnet.Subnet_Codewithmuh.id
private_ips = ["10.0.0.10"]
security_groups = [aws_security_group.SG_Codewithmuh.id]
}
Creates an ENI with the specified private IP address (10.0.0.10) in the subnet identified by the resource aws_subnet.Subnet_Codewithmuh.id.
Associates the ENI with the security group identified by the resource aws_security_group.SG_Codewithmuh.id.
8. Assign Elastic IP to ENI
# 8) Assign Elastic IP to ENI
resource "aws_eip" "EIP_A" {
vpc = true
network_interface = aws_network_interface.ENI_A.id
associate_with_private_ip = "10.0.0.10"
depends_on = [aws_internet_gateway.GW_Codewithmuh, aws_instance.Instance_A]
tags = {
Name = "EIP_A"
}
}
- Creates an Elastic IP address and associates it with the ENI identified by the resource aws_network_interface.ENI_A.id.
- Associates the Elastic IP address with the private IP address 10.0.0.10 on the ENI.
- Specifies that the Elastic IP address is associated with a VPC.
- Sets a tag for the Elastic IP address with the name âEIP_Aâ.
- Depends on the aws_internet_gateway.GW_Codewithmuh resource to be created first.
9. Create IAM Role to access S3
# 9) Creat IAM Role to acces S3
resource "aws_iam_role" "EC2-S3" {
name = "EC2-S3"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
tags = {
Name = "EC2-S3"
}
}
// IAM Profile
resource "aws_iam_instance_profile" "EC2-S3_Profile" {
name = "EC2-S3_Profile"
role = "${aws_iam_role.EC2-S3.name}"
}
// IAM Policy
resource "aws_iam_role_policy" "EC2-S3_Policy" {
name = "test_policy"
role = "${aws_iam_role.EC2-S3.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": "*"
}
]
}
EOF
}
- Creates an IAM role named âEC2-S3â with a trust policy that allows EC2 instances to assume the role.
- Sets a tag for the IAM role with the name âEC2-S3â.
- Creates an instance profile named âEC2-S3_Profileâ and associates it with the IAM role created by the resource aws_iam_role.EC2-S3.
- Creates an IAM policy named âtest_policyâ and associates it with the IAM role created by the resource aws_iam_role.EC2-S3.
- Grants permission to perform all actions (s3:) on all resources () in the S3 service.
9. Create Linux Server and Install/Enable Apache2
# 10) Create Linux Server and Install/Enable Apache2
resource "aws_instance" "Instance_A" {
ami = "ami-0947d2ba12ee1ff75"
instance_type = "t2.micro"
availability_zone = "us-east-1a"
key_name = "Codewithmuh"
iam_instance_profile = "${aws_iam_instance_profile.EC2-S3_Profile.name}"
network_interface {
device_index = 0
network_interface_id = aws_network_interface.ENI_A.id
}
user_data = <<-EOF
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd.x86_64
sudo systemctl start httpd.service
sudo systemctl enable httpd.service
sudo aws s3 sync s3://awsbucketbeta00/website /var/www/html
EOF
tags = {
Name = "Codewithmuh_1.0"
}
}
- Creates an EC2 instance using the Amazon Linux 2 AMI (ami-0947d2ba12ee1ff75).
- Sets the instance type to t2.micro.
- Specifies the availability zone to launch the instance in (us-east-1a).
- Specifies the key pair to use for SSH access (Codewithmuh).
- Specifies the IAM instance profile created in resource #9 (aws_iam_instance_profile.EC2-S3_Profile.name).
- Associates the instance with the network interface created in resource #7 (aws_network_interface.ENI_A.id).
- Defines the user_data script to install and enable Apache2, start the Apache2 service, and sync the contents of an S3 bucket to the Apache2 document root directory (/var/www/html).
- Sets a tag for the instance with the name âCodewithmuh_1.0â.
11. Enable Vpc Endpoint
# 11) Enable VCP Endpoint
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.A.id
service_name = "com.amazonaws.us-east-1.s3"
tags = {
Environment = "test"
}
}
- Creates an S3 VPC endpoint in the VPC created in resource #2 (aws_vpc.A.id).
- Specifies the service name for the S3 endpoint (com.amazonaws.us-east-1.s3).
- Sets a tag for the endpoint with the name âtestâ.
So we are done.
All code is in one file, which you can find it here.
Now letâs Validate, Plan and Apply.
Before we do, we need to create keypair, which we have defined in our Point 10.
You can create an AWS key pair using the AWS Command Line Interface (CLI) with the following command:
aws ec2 create-key-pair --key-name <KEY-PAIR-NAME> --query 'KeyMaterial' --output text > <KEY-PAIR-NAME>.pem
Replace
Now it's time to Build.
Run These commands.
1. terraform init
2. terraform validate # run this command to validate your code
3. terraform plan # run this command to check the infrastructure you are going to create
4. terraform apply # run this command to create infrastructure
Conclusion:
In this project, we have successfully created a VPC and configured various resources within it using the Terraform infrastructure as code tool. The resources created include an internet gateway, a custom route table, a subnet, a security group to allow inbound traffic on ports 22, 80, and 443, an Elastic Network Interface (ENI) with a private IP address, an Elastic IP (EIP) associated with the ENI, and an IAM role for accessing Amazon S3. Additionally, we have installed and enabled Apache2 on a Linux server and enabled a VPC endpoint.
The use of Terraform enables us to automate the deployment and management of infrastructure resources, allowing us to provision resources quickly and efficiently. This project provides an excellent example of how Terraform can be used to build, manage, and update infrastructure resources in an organized and scalable way.
You can Folllow me at:
Note: Thank You for reading!
Note: For Quries and for projects work you cna react out to me at codewithmuh@gmail.com