Setting Up an AWS Infrastructure with Terraform
Welcome to this guide where we will walk you through setting up your own AWS infrastructure using Terraform. Whether you're new to cloud provisioning or looking to refine your skills, this tutorial will help you get started. Let's dive in!
Project Introduction
In this project, we will create an AWS Virtual Private Cloud (VPC) along with several other essential resources using Terraform. We'll set up a VPC, subnet, route table, internet gateway, and security group, launch an EC2 instance within the newly created infrastructure and run the nginx container inside the EC2 instance.
What We Are Doing
We will use Terraform to automate the creation of the following resources:
VPC (Virtual Private Cloud): We'll establish a dedicated network environment within AWS for our resources.
Subnet: We'll create a subnet within the VPC to host our resources.
Route Table: We'll set up a routing table to manage the routing of network traffic.
Internet Gateway: We'll create an internet gateway to allow our resources to communicate with the internet.
Security Group: We'll configure a security group to control inbound and outbound traffic to our resources.
EC2 Instance: We'll launch an EC2 instance within the subnet, allowing us to deploy our application.
Running nginx container: After doing all these things we are going to run the nginx container inside our instance.
Resources Created
AWS VPC named
${var.env_prefix}-vac
Subnet named
${var.env_prefix}-subnet-1
Route Table named
${var.env_prefix}-rtb
Internet Gateway named
${var.env_prefix}-igw
Security Group named
${var.env_prefix}-SG
EC2 Key Pair named
project-key
EC2 Instance named
${var.env_prefix}-server
Terraform Configuration (YAML)
provider "aws" {
region = "us-east-1"
}
variable "vpc_cidr_block" {}
variable "subnet_cidr_block" {}
variable "avalibilty_zone" {}
variable "env_prefix" {}
variable "my_ip" {}
variable "instance_type"{}
variable "public_key_location"{}
variable "private_key_location"{}
resource "aws_vpc" "my_vpc" {
cidr_block = var.vpc_cidr_block
tags = {
Name: "${var.env_prefix}-vpc"
}
}
resource "aws_subnet" "my_subnet" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = var.subnet_cidr_block
availability_zone = var.avalibilty_zone
tags = {
Name: "${var.env_prefix}-subnet-1"
}
}
resource "aws_route_table" "my_route_table" {
vpc_id = aws_vpc.my_vpc.id
route {
cidr_block="0.0.0.0/0"
gateway_id = aws_internet_gateway.my_igw.id
}
tags = {
Name: "${var.env_prefix}-rtb"
}
}
# Instead of creating new route table you can use the default one
# You can configure in the same way as mentioned below
/*
resource "aws_default_route_table" "main-rtb"{
default_route_table_id = aws_vpc.my_vpc.default_route_table_id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.my_igw.id
}
tags = {
Name: "${var.env_prefix}-main-rtb"
}
}
*/
resource "aws_internet_gateway" "my_igw" {
vpc_id = aws_vpc.my_vpc.id
tags = {
Name: "${var.env_prefix}-igw"
}
}
resource "aws_route_table_association" "my_rta" {
subnet_id = aws_subnet.my_subnet.id
route_table_id = aws_route_table.my_route_table.id
}
resource "aws_security_group" "my-sg" { # if you want to use default security group then instead of "aws_security_group" use "aws_default_security_group"
# Remove the name of security group cause it is already assigned as default and reamining configuration is samename = "my-security-group"
vpc_id = aws_vpc.my_vpc.id
ingress{
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.my_ip]
}
ingress{
from_port = 8080
to_port = 8080
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"]
prefix_list_ids = []
}
tags = {
Name: "${var.env_prefix}-SG"
}
}
resource "aws_key_pair" "ssh-key" {
key_name = "project-key"
public_key = file(var.public_key_location)
}
resource "aws_instance" "myapp-server" {
ami = "ami-053b0d53c279acc90"
instance_type = var.instance_type
subnet_id=aws_subnet.my_subnet.id
vpc_security_group_ids = [aws_security_group.my-sg.id]
availability_zone = var.avalibilty_zone
associate_public_ip_address = true
key_name = aws_key_pair.ssh-key.key_name
connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
private_key = file(var.private_key_location)
}
provisioner "file" {
source ="entry-script.sh"
destination = "/home/ubuntu/entry-script-on-ec2.sh"
}
provisioner "remote-exec"{
inline = [
"chmod +x /home/ubuntu/entry-script-on-ec2.sh",
"sh /home/ubuntu/entry-script-on-ec2.sh",
]
}
provisioner "local-exec" {
command = "echo ${self.public_ip} > output.text"
}
tags = {
Name = "${var.env_prefix}-server"
}
}
output "aws_public_ip" {
value = aws_instance.myapp-server.public_ip
}
Explaining the Code
The provided Terraform code accomplishes the following:
VPC and Subnet Creation: We define a VPC and a subnet within that VPC. The subnet is associated with an availability zone.
Route Table and Internet Gateway: We create a route table and associate it with the VPC. This table includes a default route pointing to the internet gateway.
Security Group: We configure a security group allowing SSH access from your IP and opening port 8080 to the world. Outbound traffic is unrestricted.
EC2 Key Pair: We generate an EC2 key pair for secure SSH access.
EC2 Instance: We launch an EC2 instance within the subnet and associate the security group and key pair. We also copy an entry script to the instance and execute it remotely.
Understanding the Entry-Point Script
The entry-point. sh
script provided performs the following actions:
#!/bin/bash
sudo apt-get update
sudo apt install docker.io -y
sudo systemctl start docker
sudo usermod -aG docker ubuntu
sudo docker pull nginx:latest
sudo docker run -d -p 8080:8080 nginx:latest
Updates package information and installs Docker.
Starts the Docker service and adds the
Ubuntu
user to thedocker
group.Pulls the latest Nginx image and runs a container on port 8080.
Conclusion
Congratulations! You've successfully set up an AWS infrastructure using Terraform. By automating the provisioning of resources, you've saved time and ensured consistency.