Creating the public wordpress and private MySQL database with NAT gateway on AWS using terraform
--
In this article, I am going to demonstrate how to create a public subnet for wordpress and a private subnet for SQL server with NAT gateway and internet gateway using terraform.
What is Terraform?
Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions. By using the teraform we can manage the multiple clouds. By knowing 1 language we can create infrastructure in all clouds. Terraform provides the CAAS(Code As A Service) which provides the code for creating and destroying the infrastructure in just 1 click.
Problem Statement:
Performing the following steps:
1. Write an Infrastructure as code using terraform, which automatically create a VPC.
2. In that VPC we have to create 2 subnets:
1. public subnet [ Accessible for Public World! ]
2. 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. Create a NAT gateway for connect our VPC/Network to the internet world and attach this gateway to our VPC in the public network
6. Update the routing table of the private subnet, so that to access the internet it uses the nat gateway created in the public subnet
7. Launch an ec2 instance which has Wordpress setup already having the security group allowing port 80 sothat our client can connect to our wordpress site. Also attach the key to instance for further login into it.
8. 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:
We are creating this infrastructure using terraform.
Step-1:
In this project we are using the AWS cloud so we are using the provider “AWS”.
provider “aws” {
profile = “prasanth”
region = “ap-south-1”
}
Here profile is used for security for the access key and secret key.
Creating the profile:
aws configure --profile user
Then it will prompt for access key and secret key.
Step1:
Creating the VPC
resource “aws_vpc” “main” {
cidr_block = “192.168.0.0/16”
instance_tenancy = “default”
enable_dns_hostnames=”true”tags = {
Name = “main”
}
}
Step 2:
We have to create 2 subnets one private(for MySQL) and one public(for WordPress).
Private subnet:
resource "aws_subnet" "public_subnet" {depends_on=[aws_vpc.main,]vpc_id = "${aws_vpc.main.id}"cidr_block = "192.168.1.0/24"availability_zone = "ap-south-1a"map_public_ip_on_launch="true"tags={"Name"="public_subnet"}}
Private Subnet
resource "aws_subnet" "private_subnet" {depends_on=[aws_vpc.main,]vpc_id = "${aws_vpc.main.id}"cidr_block = "192.168.2.0/24"availability_zone = "ap-south-1b"tags={"Name"="private_subnet"}}
Step 3:
Creating the public facing internet gateway for private subnet
resource "aws_internet_gateway" "igw" {depends_on=[aws_vpc.main,]vpc_id = "aws_vpc.main.id"tags= {Name = "igw"}}
Step 4:
Create a routing table for Internet gateway
resource "aws_route_table" "rt_public" {depends_on = [aws_internet_gateway.igw,]vpc_id = aws_vpc.main.idroute {cidr_block = "0.0.0.0/0"gateway_id = aws_internet_gateway.igw.id}tags = {Name = "my-routing-table" // name the table}}
Here, we are creating the elastic IP which is used to make the IP permanent or static.
//Creating the elastic IPresource "aws_eip" "Elastic_IP" {
depends_on = [
aws_internet_gateway.igw,
]
vpc=true
tags = {
"Name" = "Elastic_IP"
}
}
Step 5:
Creating the NAT gateway
resource "aws_nat_gateway" "NAT_GW" {depends_on = [aws_eip.Elastic_IP,aws_subnet.public_subnet,]allocation_id = aws_eip.Elastic_IP.idsubnet_id = aws_subnet.public_subnet.idtags = {"Name" = "NAT_GW"}}
Routing table association with private subnet
resource "aws_route_table_association" "private_subnet" {depends_on=[aws_subnet.private_subnet,aws_route_table.rt-private,]subnet_id = "${aws_subnet.private_subnet.id}"route_table_id = "${aws_route_table.rt-private.id}"}
Creating the routing tables for public subnet
//Creating the routing table for public subnetresource "aws_route_table" "public_subnet" {
depends_on=[
aws_vpc.main,
aws_internet_gateway.igw,
]
vpc_id = "aws_vpc.main.id"
route {
cidr_block = "0.0.0.0/24"
gateway_id = "aws_internet_gateway.igw.id"
}
}
Routing table association with public subnet.
resource "aws_route_table_association" "public_subnet" {
depends_on=[
aws_subnet.public_subnet,
aws_route_table.rt_public,
]
subnet_id = "aws_subnet.public_subnet.id"
route_table_id = "${aws_route_table.public_subnet.id}"
}
Step 6:
Creating the security group for the wordpress instance
resource "aws_security_group" "WP_SG" {depends_on = [aws_vpc.main,]name = "WP_SG"description = "Allow TLS inbound traffic"vpc_id = aws_vpc.main.idingress {description = "SSH"from_port = 22to_port = 22protocol = "tcp"cidr_blocks = ["0.0.0.0/0"]}ingress {description = "http"from_port = 80to_port = 80protocol = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port = 0to_port = 0protocol = "-1"cidr_blocks = ["0.0.0.0/0"]}tags = {Name = "WP_SG"}}
Creating the security group for the MySQL instance
resource "aws_security_group" "MYSQL_SG" {depends_on = [aws_vpc.main,aws_security_group.WP_SG,aws_security_group.bastion_SG,]name = "SG-Database"description = "Allow SG-Wordpress inbound traffic"vpc_id = aws_vpc.main.idingress { // will allow traffic by WordPressdescription = "MySQL"security_groups = [aws_security_group.WP_SG.id,]from_port = 3306to_port = 3306protocol = "tcp"}ingress { // will allow SSH only from Bastion Hostdescription = "SSH"security_groups = [aws_security_group.bastion_SG.id,]from_port = 22to_port = 22protocol = "tcp"}egress {from_port = 0to_port = 0protocol = "-1"cidr_blocks = ["0.0.0.0/0"]}tags = {Name = "MYSQL_SG"}}
Creating the security groups for bastion host .
A bastion host is a special-purpose computer on a network specifically designed and configured to withstand attacks. The computer generally hosts a single application, for example a proxy server, and all other services are removed or limited to reduce the threat to the computer.
resource "aws_security_group" "bastion_SG" {depends_on = [aws_vpc.main,aws_security_group.WP_SG,]name = "Bastion_SG"description = "SG for Bastion Host"vpc_id = aws_vpc.main.idingress {description = "ssh"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"]}
tags = {Name = "bastion-sg"}}
Step 7:
Before creating the instance we need to create the key pair.
Creating the key pair
resource "tls_private_key" "mykey"{algorithm= "RSA"}resource "aws_key_pair" "generated_key"{key_name= "mytask4key"public_key= "${tls_private_key.mykey.public_key_openssh}"depends_on = [tls_private_key.mykey]}
Creating the Wordpress instance
resource "aws_instance" "WP_instance" {depends_on = [aws_key_pair.generated_key,aws_subnet.public_subnet,aws_security_group.WP_SG,]ami = "ami-000cbce3e1b899ebd"instance_type = "t2.micro"associate_public_ip_address = truesubnet_id = aws_subnet.public_subnet.idvpc_security_group_ids = [ // security-groupsaws_security_group.WP_SG.id, // group for WordPress]key_name = "mytask4key" // key to use for SSHtags ={Name = "WP_instance" // name the instance}}
Creating the MYSQL instance
resource "aws_instance" "MYSQL_instance" {depends_on = [aws_key_pair.generated_key,aws_security_group.MYSQL_SG,aws_subnet.private_subnet,]ami = "ami-08706cb5f68222d09"instance_type = "t2.micro"associate_public_ip_address = falsesubnet_id = aws_subnet.private_subnet.idvpc_security_group_ids = [ // security-groupsaws_security_group.MYSQL_SG.id, // group for MySQL]key_name = "mytask4key" // key to use for SSHtags ={Name = "mysql_instance" // name of instance}}
Creating the instance for Bastion host.
resource "aws_instance" "bastion_host_instance" {depends_on = [aws_key_pair.generated_key,aws_security_group.bastion_SG,aws_subnet.public_subnet,]ami = "ami-0732b62d310b80e97"instance_type = "t2.micro"availability_zone = "ap-south-1a"subnet_id = aws_subnet.public_subnet.idsecurity_groups = [ // security groupsaws_security_group.bastion_SG.id, // group for Bastion]key_name = "mytask4key" // key to use for SSHtags = {Name = "bastion_host_instance" // name of Instance}}
That’s all our code is complete
For running the code we need to use
terraform init
It initializes the terraform by installing the required resources
terraform validate
For checking the errors in code
terraform plan
This commands shows the list of services that gonna create
terraform apply --auto-approve
This is the final command for deploying our entire infrastructure into AWS
Here some of the screenshots of the deployed infrastructure
That’s all guys, we have successfully completed the task
Thank you for reading this article.I hope it helped you.