Integrating a VPC with EC2 via Terraform
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:
- 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.
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 .
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>"
}
}
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:
Now for the last few steps , which is initializing and applying .
Command for initializing :
terraform init
Command for applying :
terraform apply
Now for the output
Once we’re done with working on our infrastructure we can delete the whole thing by :
terraform destroy
This shows how easily we can launch a infrastructure by executing a few HCL codes in Terraform.