Launch Public and Private Subnet in a VPC using Terraform
In this article, we will discuss how to launch a website(WordPress site) by considering the security measures. This project has the following key points:
- Deploying a WordPress site in a Public Subnet
- Deploying a MySQL database in a Private Subnet
Let’s start the project by writing a Terraform code in a vpc.tf file.
- Configuring AWS:
// Configuring the provider information
provider "aws" {
region = "ap-south-1"
profile = "ankush"
}
Specifying the provider we are going to use(in my case AWS), default region, and the profile. The profile contains all of the credentials to log in to the AWS.
Crating new Profile: Run the following command and follow the steps.
$ aws configure --profile ankush
- Creating Private EC2 Key-Pair:
// Creating the EC2 private keyvariable "key_name" {default = "Terraform_vpc"}resource "tls_private_key" "ec2_private_key" {algorithm = "RSA"rsa_bits = 4096provisioner "local-exec" {command = "echo '${tls_private_key.ec2_private_key.private_key_pem}' > ~/Desktop/task2/${var.key_name}.pem"}}// Making the access of .pem key as a privateresource "null_resource" "key-perm" {depends_on = [tls_private_key.ec2_private_key,]provisioner "local-exec" {command = "chmod 400 ~/Desktop/task2/${var.key_name}.pem"}}module "key_pair" {source = "terraform-aws-modules/key-pair/aws"key_name = var.key_namepublic_key = tls_private_key.ec2_private_key.public_key_openssh}
Above code will create a private EC2 Key-Pair named Terraform_vpc
- Creating a VPC:
Creating a VPC with the CIDR block length 192.168.0.0/16
resource "aws_vpc" "myVpc" {cidr_block = "192.168.0.0/16"instance_tenancy = "default"tags = {Name = "my-vpc"}enable_dns_hostnames = true}
- Creating Subnet:
Now, we will create two subnets in a VPC named my-vpc. Out of these two subnets, one subnet is a public subnet and another is a private subnet. The public subnet have access to the internet where the private subnet is isolated.
Let's create a public subnet named my-subnet1
resource "aws_subnet" "mySubnet1" {depends_on = [aws_vpc.myVpc,]vpc_id = "${aws_vpc.myVpc.id}"cidr_block = "192.168.0.0/24"availability_zone_id = "aps1-az1"tags = {Name = "my-subnet1"}map_public_ip_on_launch = true}
In this public subnet, we will launch the WordPress site.
Now, create private subnet named my-subnet2
resource "aws_subnet" "mySubnet2" {depends_on = [aws_vpc.myVpc,]vpc_id = "${aws_vpc.myVpc.id}"cidr_block = "192.168.1.0/24"availability_zone_id = "aps1-az1"tags = {Name = "my-subnet2"}}
In this private subnet, we will launch the MySQL database.
- Creating an Internet Gateway and Route table:
Until now, we had set up labs(Subnet) for our WordPress site. For providing Internet connectivity inside public subnet we required to create an Internet Gateway. So, let’s create Internet Gateway inside the my-vpc.
resource "aws_internet_gateway" "myInternetGateway" {depends_on = [aws_vpc.myVpc,]vpc_id = "${aws_vpc.myVpc.id}"tags = {Name = "my-internet-gateway"}}
The above code will create an Internet Gateway named my-internet-gateway.
After that create a Route Table and associate this Route table with the public subnet(my-subnet1).
resource "aws_route_table" "myRouteTable" {depends_on = [aws_vpc.myVpc,aws_internet_gateway.myInternetGateway,]vpc_id = "${aws_vpc.myVpc.id}"route {cidr_block = "0.0.0.0/0"gateway_id = "${aws_internet_gateway.myInternetGateway.id}"}tags = {Name = "my-route-table"}}
Now, the Route Table named my-route-table is created.
Associate this route table with the public subnet.
resource "aws_route_table_association" "associateRouteTableWithSubnet" {depends_on = [aws_subnet.mySubnet1,aws_route_table.myRouteTable,]subnet_id = aws_subnet.mySubnet1.idroute_table_id = aws_route_table.myRouteTable.id}
Finally, the complete lab for launching a WordPress site is set up successfully.
- Creating Security Groups for WordPress and MySQL Instances:
Security Group for WordPress Instance:
As we know, WordPress works on port 80 by default. So, we will allow inbound traffic from port 80. Also, for management purposes, we required to login inside the instance. So, we will allow port 22 for SSH.
resource "aws_security_group" "allowHttp" {depends_on = [aws_vpc.myVpc,]
name = "allow_http"description = "Allow http inbound traffic"vpc_id = "${aws_vpc.myVpc.id}"
ingress {description = "TCP from VPC"from_port = 80to_port = 80protocol = "tcp"cidr_blocks = ["0.0.0.0/0"]}ingress {description = "SSH from VPC"from_port = 22to_port = 22protocol = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port = 0to_port = 0protocol = "-1"cidr_blocks = ["0.0.0.0/0"]}}
Security Group for MySQL instance:
As we are running MySQL instance in a private subnet, we required that MySQL can only be accessed by the WordPress instance. So, we will only allow the inbound traffic from port 3306 on which MySQL works by default.
resource "aws_security_group" "allowMysql" {depends_on = [aws_vpc.myVpc,]name = "allow_mysql"description = "Allow mysql inbound traffic"vpc_id = "${aws_vpc.myVpc.id}"ingress {description = "TCP from VPC"from_port = 3306to_port = 3306protocol = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port = 0to_port = 0protocol = "-1"cidr_blocks = ["0.0.0.0/0"]}}
Launching MySQL Instance:
The WordPress required MySQL database to be set up first. So, we will launch a MySQL instance first.
resource "aws_instance" "mysql" {depends_on = [aws_security_group.allowMysql,]ami = "ami-0af4f2ae8f9fac390"instance_type = "t2.micro"vpc_security_group_ids = ["${aws_security_group.allowMysql.id}"]subnet_id = "${aws_subnet.mySubnet2.id}"tags = {Name = "mysql"}}
Launching WordPress Instance:
Finally, we will launch the WordPress Instance and this will successfully launch the WordPress site.
resource "aws_instance" "wordpress" {depends_on = [aws_security_group.allowHttp,aws_instance.mysql,]ami = "ami-ff82f990"instance_type = "t2.micro"key_name = var.key_namevpc_security_group_ids = ["${aws_security_group.allowHttp.id}"]subnet_id = "${aws_subnet.mySubnet1.id}"tags = {Name = "wordpress"}}
Finally, the Terraform code for launching the WordPress site using public and private subnet in the same VPC is completed.
Run the Terraform Code:
Step 1: Initializing the modules
$ terraform init
Step 2: Validating the Terraform code
$ terraform validate
Step 3: Run the Terraform code
$ terraform apply --auto-approve
Step 4: Check if the WordPress and MySQL instances are launched successfully by login into the AWS Console.
As we can see in the above image, the WordPress instance has public IP allocated. So, WordPress can be accessed from the public world using public IP.
But, the MySQL instance doesn’t have any public IP assigned. So, there is no way we can access the MySQL instance from the public world.
Step 5: Accessing the WordPress Site
Now, open the public IP of the WordPress instance form the browser.
The WordPress site is launched successfully and can be accessed by using the public IP of the WordPress instance.
Removing all of the Infrastructure:
Deleting all of the infrastructure managed by Terraform is pretty easy. With just a single command we can take down the whole infrastructure.
$ terraform destroy --auto-approve
Github link for the Terraform code: https://github.com/cankush625/Terraform/tree/master/task3_vpc
If you liked this article, please applaud it.
You can also follow me on Twitter at @cankush625 or find me on LinkedIn.