Integrating a VPC with EC2 via Terraform

B.V.Rohan Bharadwaj
7 min readJul 17, 2020

What is Terraform?

It’s a tool meant for constructing an IaC (Infrastructure as Code ) in order to provision and manage any cloud based application , infrastructure, or services. Terraform makes it much easier work on cloud as it runs on simple standardized commands provided by Harshicorp in a declarative language called HCL ( Hashicorp Configuration Language ) .

Now comes the question of “What’s an IaC ?”

Infrastructure as code means writing code to provision, manage and deploy IT infrastructure.Which means, This is meant to be a blueprint of how your Data Center is to be visioned or created . More over , infrastructures can be reused and also shared making it highly advantageous .

Virtual Private Cloud

Amazon’s VPC lets you provision a logically isolated section of AWS’s Cloud ,where we can launch AWS resources on a virtual network that you define. We have total control over the virtual networking environment, including selection of the IP address range, creation of subnets, configuration of route tables ,and network gateways. We can use both IPv4 and IPv6 in our VPC which provides secure ( in the form of : security groups and network access control lists ) and easy access to resources and applications .

It has many use cases like web application,corporate networks which can encrypts all communication between the application servers and so on .

Task Objectives:

We have to create a web portal for our company with all the security as much as possible.So, we use Wordpress software with dedicated database server.Database should not be accessible from the outside world for security purposes.We only need to public the WordPress to clients.

Steps:

1] Write a Infrastructure as code using terraform, which automatically create a VPC.

2] In that VPC we have to create 2 subnets:

a] Public subnet [ Accessible for Public World ]

b] Private subnet [ Restricted for Public World ]

3] Create a public facing internet gateway for connect our VPC/Network to the internet world and attach this gateway to our VPC.

4] Create a routing table for Internet gateway so that instance can connect to outside world, update and associate it with public subnet.

5] Launch an ec2 instance which has Wordpress setup already having the security group allowing port 80 so that our client can connect to our wordpress site.

Also attach the key to instance for further login into it.

6] Launch an ec2 instance which has MYSQL setup already with security group allowing port 3306 in private subnet so that our wordpress vm can connect with the same.

Also attach the key with the same.

Note: Wordpress instance has to be part of public subnet so that our client can connect our site.

Mysql instance has to be part of private subnet so that outside world can’t connect to it.

Don’t forgot to add auto ip assign and auto dns name assignment option to be enabled.

Procedure:

  1. As Terraform is a pluggin based application first we have to install the required plugins ( in our case being AWS ) . This is done via HCL code
provider "aws" {
region = "ap-south-1"
}

To make it easy for myself , I’m working with the “default” user profile.

But you may try the other way around , which is by specifying the profile in it

provider "aws" {
region = "ap-south-1"
profile = "<your_profile_name>"
}

2. Next we can create a key pair for logging in to our instance when needed to.

resource "tls_private_key" "<keyname>" {
algorithm = "RSA"
}
resource "aws_key_pair" "generated_key" {
key_name = "<keyname>"
public_key = "${tls_private_key.<keyname>.public_key_openssh}"
depends_on = [
tls_private_key.<keyname>
]
}
resource "local_file" "key" {
content = "${tls_private_key.<keyname>.private_key_pem}"
filename = "<keyname>.pem"
file_permission ="0400"
depends_on = [
tls_private_key.<keyname>
]
}

Once you run it , a new Key-Pain is generated and stored in the current working directory with an .pem extension.

3. It’s time to create our VPC , in which we launch multiple subnets . Since each VPC is isolated from one and other also from the cloud as well . But we must specify the range of our IP for using a VN

resource "aws_vpc" "<vpc_name>" {
cidr_block = "<the_IP_for_your_vpc>"
instance_tenancy = "default"
enable_dns_hostnames = "true"

tags = {
Name = "<vpc_name>"
}
}

Here, CIDR stands for Classless Inter-Domain Routing. A VPC is always assigned with a network name ranging to at max of : 255.255.0.0255.255.0.0 and can use up to 65536 IPs.

This is my VPC ,Conveniently named as my_vpc

4. Now we have to create Security Group for it .

An SG is essentially just a (virtual) firewall meant for the instance we create inorder to control the ingress and egress traffic. We have to set the inbound and outbound rules though , which are the types of traffics permitted to enter/exit from our instance .

resource "aws_security_group" "<sg_name>" {
name = "<sg_name>""
description = "This firewall allows SSH, HTTP and MYSQL"
vpc_id = "${aws_vpc.my_vpc.id}"

ingress {
description = "SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

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

ingress {
description = "TCP"
from_port = 3306
to_port = 3306
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_name>""
}
}

In that, we are creating an SG which can allow HTTP , SSH protocols and MySQL traffics .

In my case , I’ve decided to name my SG as sg

5. In this step , we are creating subnets based on our VPC .One of them being Public and the other being Private.

resource "aws_subnet" "public" {
vpc_id = "${aws_vpc.my_vpc.id}"
cidr_block = "192.168.0.0/24"
availability_zone = "ap-south-1a"
map_public_ip_on_launch = "true"

tags = {
Name = "my_public_subnet"
}
}
resource "aws_subnet" "private" {
vpc_id = "${aws_vpc.my_vpc.id}"
cidr_block = "192.168.1.0/24"
availability_zone = "ap-south-1b"

tags = {
Name = "my_private_subnet"
}
}

Here, we are creating two subnets in different AZ’s .

In a network there can be 256 Ips, but we are presented with 251. The other 5 being reserved for :

i) Network name

ii) Router

iii) DHCP server

iv) Broadcasting

v) Future use

In my case, my subnet’s ip is “192.168.0.0” , with the subnet mask being 255.255.255.0

6. Internet Gateway

It’s a part of VPC which establishes communication between the VPC and Internet .

resource "aws_internet_gateway" "<internet_gateway_name>" {
vpc_id = "${aws_vpc.<vpc_name>.id}"

tags = {
Name = "<internet_gateway_name>"
}
}
I named mine as “gateway

7. Creating a Route Table

A Route Table is meant to control where the traffic is diverted to . Every subnet in the VPC must associate with the Route Table, this allows it to control the routing for traffic into the subnets.

resource "aws_route_table" "<name_of_rt>" {
vpc_id = "${aws_vpc.<vpc_name>.id}"

route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.<internet_gateway_name>.id}"
}

tags = {
Name = "<name_of_rt>"
}
}

Here, we are creating a route table in our VPC , which will lead the traffic to the Internet Gateway .

Once that’s done we can Associate it to our subnets.

resource "aws_route_table_association" "a" {
subnet_id = "${aws_subnet.public.id}"
route_table_id = "${aws_route_table.rt.id}"
}resource "aws_route_table_association" "b" {
subnet_id = "${aws_subnet.private.id}"
route_table_id = "${aws_route_table.rt.id}"
}

8. Next we are creating instances ( 2 to be exact )

i) WordPress Instance:

resource "aws_instance" "wordpress" {
ami = "ami-03a115bbd6928e698"
instance_type = "t2.micro"
key_name = "${aws_key_pair.generated_key.key_name}"
vpc_security_group_ids = [ "${aws_security_group.sg.id}" ]
subnet_id = "${aws_subnet.public.id}"

tags = {
Name = "<Wordpress_instance_name>"
}
}

ii) MySQL Instance:

resource "aws_instance" "mysql" {
ami = "ami-04e98b8bcc00d2678"
instance_type = "t2.micro"
key_name = "${aws_key_pair.generated_key.key_name}"
vpc_security_group_ids = [ "${aws_security_group.mysg.id}" ]
subnet_id = "${aws_subnet.private.id}"

tags = {
Name = "<MySQL_instance_name>"
}
}

The Instances:

The instances used by me are named Mysql and Wordpress

Now for the last few steps , which is initializing and applying .

Command for initializing :

terraform init

Command for applying :

terraform apply
Initializing
Done Applying

Now for the output

the website before logging in
After logging in and creating a blog

Once we’re done with working on our infrastructure we can delete the whole thing by :

terraform destroy
Destroyed in seconds

This shows how easily we can launch a infrastructure by executing a few HCL codes in Terraform.

Thank you for the time!

--

--