BorenaK / Creating-EC2-VPC-via-Terraform

Deploying EC2 Instances, VPC with Public and Private Subnets via Terraform

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

VPC & EC2 Creation via Terraform

Build Status

In this project we are going to create VPC and EC2 instances through terraform, we need 3 EC2 instances one webserver, one db server and a bastion server that can give us ssh access to both webserver and db server. The database server is created in a private subnet and other instances are in public subnet. All the instances are spread over 3 Avaialability Zones, the Availability Zones are automatically fetched via the data source.

List of AWS resources created through terraform

  • EC2 Instances
  • Security Group
  • AMI (Amazon Machine Image)
  • Key-Pair
  • Internet Gateway
  • Nat Gateway
  • Route Tables
  • VPC

Features

  • Easy to customise and use.
  • Each subnet CIDR block created through automation.
  • Using tfvars file to access and modify variables.
  • Project and name tag is appended to the resources that we are creating.

Pre-requisites for this project

  • Need AWS CLI access or IAM user access with attached policies for the creation of VPC.
  • Terraform need to be installed in your system.
  • Knowledge to the working principles of each AWS services especially VPC, EC2 and IP Subnetting.

Creating variables.tf

First lets create a file for declaring our variables, Create a variables.tf file and we define the following variables

variable "region" {}
variable "access_key" {}
variable "secret_key" {}
variable "project" {}
variable "vpc_cidr" {}
variable "sbit" {}
variable "name" {}

values declared here are passing through the terrafrom.tfvars file.

Creating provider.tf

Now lets create our provider.tf file which defines our provider.

provider "aws" {
  region     = var.region
  access_key = var.access_key
  secret_key = var.secret_key
}

Creating terraform.tfvars

By default terraform.tfvars will load the variables to the the resources. we can define our subnet bit here so that it automates the creation of CIDR Block

region     = "put-your-region-here"
access_key = "put-your-access-key-here"
secret_key = "put-your-secret-key-here"
project =    "put-your-project-tag"
name     =   "put-your-name-tag"
vpc_cidr =   "X.X.X.X/X"
sbit     =   "X"

User Customization

Customization can be done in this file as per the requirements of the user which includes selecting the region, changing the project name & automating subnetting. All can be done in this single file.

Now we move to initialize terraform configuration files using the below command.

terraform init.

Once successfully initialized we move on to create our infrastructure and EC2 instances. Lets start by creating our main.tf file with the details below:

Creating VPC

resource "aws_vpc" "vpc" {

  cidr_block       = var.vpc_cidr
  instance_tenancy = "default"
  enable_dns_support = true
  enable_dns_hostnames = true
  tags = {
    Name = "${var.project}-vpc"
    Project  = "${var.name}"
  }
}

To Fetch Availability Zones for creation of subnets

data "aws_availability_zones" "available" {
  state = "available"
}

To Create Internet Gateway For VPC

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
  tags = {
    Name = "${var.project}-igw"
    Project  = "${var.name}"
  }
}

The infrastructure we are creating requires 3 public and 3 private subnets as such i have choosen the region "us-east-1" which gives us 6 availability zones. You can choose your region and modify according to the Availability Zone. As mentioned earlier we have already provided the CIDR block in our terraform.tfvars file so that we dont need to calculate the subnets, here we use terraform to automate the subnetting.

Creating "pub1" Public Subnet

resource "aws_subnet" "pub1" {
	vpc_id     = aws_vpc.vpc.id
	cidr_block = cidrsubnet(var.vpc_cidr , var.sbit , 0)
	availability_zone = data.aws_availability_zones.available.names[0]
	map_public_ip_on_launch = true
  tags = {
    Name = "${var.project}-pub1"
    Project  = "${var.name}"
  }
}

Creating "pub2" Public Subnet

resource "aws_subnet" "pub2" {
	vpc_id     = aws_vpc.vpc.id
	cidr_block = cidrsubnet(var.vpc_cidr , var.sbit , 1)
	availability_zone = data.aws_availability_zones.available.names[1]
	map_public_ip_on_launch = true
  tags = {
    Name = "${var.project}-pub2"
    Project  = "${var.name}"
  }
}

Creating "pub3" Public Subnet

resource "aws_subnet" "pub3" {
	vpc_id     = aws_vpc.vpc.id
	cidr_block = cidrsubnet(var.vpc_cidr , var.sbit , 2)
	availability_zone = data.aws_availability_zones.available.names[2]
	map_public_ip_on_launch = true
  tags = {
    Name = "${var.project}-pub3"
    Project  = "${var.name}"
  }
}

Creating "priv1" Private Subnet

resource "aws_subnet" "priv1" {
	vpc_id     = aws_vpc.vpc.id
	cidr_block = cidrsubnet(var.vpc_cidr , var.sbit , 3)
	availability_zone = data.aws_availability_zones.available.names[3]
	map_public_ip_on_launch = true
  tags = {
    Name = "${var.project}-priv1"
    Project  = "${var.name}"
  }
}

Creating "priv2" Private Subnet

resource "aws_subnet" "priv2" {
	vpc_id     = aws_vpc.vpc.id
	cidr_block = cidrsubnet(var.vpc_cidr , var.sbit , 4)
	availability_zone = data.aws_availability_zones.available.names[4]
	map_public_ip_on_launch = true
  tags = {
    Name = "${var.project}-priv2"
    Project  = "${var.name}"
  }
}

Creating "priv3" Private Subnet

resource "aws_subnet" "priv3" {
	vpc_id     = aws_vpc.vpc.id
	cidr_block = cidrsubnet(var.vpc_cidr , var.sbit , 5)
	availability_zone = data.aws_availability_zones.available.names[5]
	map_public_ip_on_launch = true
  tags = {
    Name = "${var.project}-priv3"
    Project  = "${var.name}"
  }
}

Creating Elastic IP For Nat Gateway

resource "aws_eip" "eip" {
  vpc      = true
  tags     = {
    Name = "${var.project}-eip"
    Project  = "${var.name}"
  }
}

Attaching Elastic IP to NAT gateway

resource "aws_nat_gateway" "ngw" {
  allocation_id = aws_eip.eip.id
  subnet_id     = aws_subnet.pub1.id
  tags = {
    Name = "${var.project}-ngw"
    Project  = "${var.name}"
  }
}

Creating Public Route Table

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.vpc.id
  route  {
      cidr_block = "0.0.0.0/0"
      gateway_id = aws_internet_gateway.igw.id
  }
  tags = {
    Name = "${var.project}-public-rtb"
    Project  = "${var.name}"
  }
}

Creating Private Route Table

resource "aws_route_table" "private" {
  vpc_id = aws_vpc.vpc.id
  route  {
      cidr_block = "0.0.0.0/0"
      gateway_id = aws_nat_gateway.ngw.id
  }
  tags = {
    Name = "${var.project}-private-rtb"
    Project  = "${var.name}"
  }
}

Creating Public Route Table Association

resource "aws_route_table_association" "pub1" {
  subnet_id      = aws_subnet.pub1.id
  route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "pub2" {
  subnet_id      = aws_subnet.pub2.id
  route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "pub3" {
  subnet_id      = aws_subnet.pub3.id
  route_table_id = aws_route_table.public.id
}

Creating Private Route Table Association

resource "aws_route_table_association" "priv1" {
  subnet_id      = aws_subnet.priv1.id
  route_table_id = aws_route_table.private.id
}
resource "aws_route_table_association" "priv2" {
  subnet_id      = aws_subnet.priv2.id
  route_table_id = aws_route_table.private.id
}
resource "aws_route_table_association" "priv3" {
  subnet_id      = aws_subnet.priv3.id
  route_table_id = aws_route_table.private.id
}

Creating Key-Pair for Our EC2 Instances

resource "aws_key_pair" "key" {
	key_name =   "terraform-key"
	public_key = file("terraform.pub")
tags = {
	Name = "${var.project}-key"
        Project  = "${var.name}"
  }
 }

Creating Security Group for Bastion Server

resource "aws_security_group" "bastion" {

  name        = "${var.name}-bastion"
  description = "Allows access to port 22"
  vpc_id      =  aws_vpc.vpc.id

  ingress {
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  tags = {
    Name = "${var.project}-bastion"
  }
}

Creating Security Group for Webserver

resource "aws_security_group" "webserver" {

  name        = "${var.name}-webserver"
  description = "Allows access to ports 22,80 & 443"
  vpc_id      = aws_vpc.vpc.id

  ingress {
    from_port        = 80
    to_port          = 80
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  ingress {
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
    ingress {
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    security_groups  = [ aws_security_group.bastion.id ]
  } 
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  tags = {
    Name = "${var.project}-webserver"
  }
}

Creating Security Group for Database Server

resource "aws_security_group" "dbserver" {

  name        = "${var.name}-dbserver"
  description = "Allows access to port 3306 and 22"
  vpc_id      =  aws_vpc.vpc.id

  ingress {
    from_port        = 3306
    to_port          = 3306
    protocol         = "tcp"
    security_groups  = [ aws_security_group.webserver.id ]
  }
 ingress {
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    security_groups  = [ aws_security_group.bastion.id ]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  tags = {
    Name = "${var.project}-dbserver"
  }
}

Creating EC2 Instance Bastion Server

resource "aws_instance" "bastion" {

    ami                          =  "ami-0c2b8ca1dad447f8a"
    instance_type                =  "t2.micro"
    subnet_id      		 =  aws_subnet.pub2.id
    key_name                     =  aws_key_pair.key.key_name
    associate_public_ip_address  =  true
    vpc_security_group_ids       =  [ aws_security_group.bastion.id ]
    tags  = {
       Name = "${var.project}-bastion"
       Project  = "${var.name}"
    }
}

Creating EC2 Instance Webserver

resource "aws_instance" "webserver" {

    ami                          =  "ami-0c2b8ca1dad447f8a"
    instance_type                =  "t2.micro"
    subnet_id      		 =  aws_subnet.pub1.id
    key_name                     =  aws_key_pair.key.key_name
    associate_public_ip_address  =  true
    vpc_security_group_ids       =  [ aws_security_group.webserver.id ]
    tags  = {
       Name     = "${var.project}-webserver"
       Project  = "${var.name}"
    }
}

Creating EC2 Instance Database Server

resource "aws_instance" "dbserver" {

    ami                          =  "ami-0c2b8ca1dad447f8a"
    instance_type                =   "t2.micro"
    subnet_id      		 =  aws_subnet.priv1.id
    key_name                     =  aws_key_pair.key.key_name
    associate_public_ip_address  =  false
    vpc_security_group_ids       =  [ aws_security_group.dbserver.id ]
    tags  = {
       Name = "${var.project}-dbserver"
       Project  = "${var.name}"
    }
}

Creating an output file (output.tf) to list the created resources

output "aws_eip" {
value = aws_eip.eip.public_ip
}

output "aws_vpc" {
value = aws_vpc.vpc.id
}

output "aws_internet_gateway" {
value = aws_internet_gateway.igw.id
}

output "aws_nat_gateway" {
value = aws_nat_gateway.nat.id
}

output "aws_route_table_public" {
value = aws_route_table.public.id
}

output "aws_route_table_private" {
value = aws_route_table.private.id
}

output "aws_instance" {
value = aws_route_table.bastion.id
}

output "aws_instance" {
value = aws_route_table.webserver.id
}

output "aws_instance" {
value = aws_route_table.dbserver.id
}

Now lets validate the terraform files using

terraform validate

Plan the architecture

terraform plan

Applying the above architecture to our AWS

terraform apply

About

Deploying EC2 Instances, VPC with Public and Private Subnets via Terraform


Languages

Language:HCL 100.0%