Create a vpc,private and public subnet inside the vpc,use a bastion user to establish connection to the private subnet
Task Description :
Perform task-3 with an additional feature to be added that is NAT Gateway to provide the internet access to instances running in the private subnet.
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 and mysql instance has to be part of private subnet so that outside world can't connect to it.
Here I have used most of the concept of another task I did earlier,things like aws configure,basics and prerequisites can be done from my previous task(task3 link):
https://www.dhirubhai.net/pulse/creating-our-own-vpcnetworkcreating-two-subnet-word-press-patnaik
What is a bastion user?
A bastion host is a server whose purpose is to provide access to a private network from an external network, such as the Internet. Because of its exposure to potential attack, a bastion host must minimize the chances of penetration. For example, you can use a bastion host to mitigate the risk of allowing SSH connections from an external network to the Linux instances launched in a private subnet of your Amazon Virtual Private Cloud (VPC).
for more info check the site:https://aws.amazon.com/blogs/security/how-to-record-ssh-sessions-established-through-a-bastion-host/
Process:
Step 1:
Inside your terraform file,Create a VPC by using terraform aws_vpc resource
provider "aws" { profile = "Asish" region = "ap-south-1" } resource "aws_vpc" "task4_vpc" { cidr_block = "192.168.0.0/16" instance_tenancy = "default" enable_dns_hostnames= "true" tags = { Name = "task4_vpc" } }
Here,enable_dns_hostnames is made true in order to allow DNS host names in vpc
Creating public subnet for wordpress using the vpc we created:
resource "aws_subnet" "public_subnet" { vpc_id = "${aws_vpc.task4_vpc.id}" cidr_block = "192.168.1.0/24" availability_zone= "ap-south-1a" map_public_ip_on_launch= "true" tags = { Name = "public_subnet" } }
->>as we want the subnet to be public,map_public_ip_on_launch is enabled due to which it automatically gets a public IP by DHCP when it is created
creating private subnet for SQL db using the vpc we created:
resource "aws_subnet" "private_subnet" { vpc_id = "${aws_vpc.task4_vpc.id}" cidr_block = "192.168.2.0/24" availability_zone= "ap-south-1b" tags = { Name = "private_subnet" } }
->>here,as you can see map_public_ip_on_launch is not enabled so it is disabled by default and due to this no public IP is assigned to it,which prevents it from other users to connect to it,making it more secure
step 2:
Create an internal gateway for the vpc:
resource "aws_internet_gateway" "task4_gw" { vpc_id = "${aws_vpc.task4_vpc.id}" tags = { Name = "task4_gw" } }
an internet gateway for our vpc is automatically created and attached to our vpc.
create a route table and associate it with public subnet:
resource "aws_route_table" "task4_routetable" { vpc_id = "${aws_vpc.task4_vpc.id}" route { cidr_block = "0.0.0.0/0" gateway_id = "${aws_internet_gateway.task4_gw.id}" } tags = { Name = "task4_routetable" } } resource "aws_route_table_association" "task4_route_public"{ subnet_id= aws_subnet.public_subnet.id route_table_id = "${aws_route_table.task4_routetable.id}" }
step 3:
create a private key for the task:
resource "tls_private_key" "mytask4key"{ algorithm= "RSA" } resource "aws_key_pair" "generated_key"{ key_name= "mytask4key" public_key= "${tls_private_key.mytask4key.public_key_openssh}" depends_on = [ tls_private_key.mytask4key ] } resource "local_file" "store_key_value"{ content= "${tls_private_key.mytask4key.private_key_pem}" filename= "mytask4key.pem" file_permission= "0400" depends_on = [ tls_private_key.mytask4key ] }
->>here I have use tls_private_key resource of AWS to generate a private key for me and stored it in my local system by using local_file resource with file name mytask4key,pem and file permission of readi.e.("0400")
step 4:
create a security group for wordpress:
resource "aws_security_group" "wordpresssg" { name = "wordpresssg" description = "Security Group for Wordpress site" vpc_id = "${aws_vpc.task4_vpc.id}" ingress { description = "SSH Protocol" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "HTTP Protocol" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress{ description="ICMP" from_port = 0 to_port = 0 protocol = "-1" 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 = "wordpress_sg" } }
->>SSH protocol needed to connect to this instance from outside of instance,http protocol needed to deploy our wordpress site using http,ICMP protocol(ICMP is a transport level protocol within TCP/IP which communicates information about network connectivity issues back to the source of the compromised transmission.) which we need to ping.
create security group of SQL database:
resource "aws_security_group" "SQLsg" { name = "SQLsg" description = "Security Group for SQL DB" vpc_id = "${aws_vpc.task4_vpc.id}" ingress { description = "SQL" from_port = 3306 to_port = 3306 protocol = "tcp" security_groups=["${aws_security_group.wordpresssg.id}"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "SQL_sg" } }
->>here 3306 port is used to connect wordpress and SQL db by using wordpresssg security group and not ther ports are provided here for security
create a security group for bastion host:
resource "aws_security_group" "bastionsg" { name = "bastionsg" description = "Security Group for Bastion Instance" vpc_id = "${aws_vpc.task4_vpc.id}" ingress { description = "SSH Protocol" from_port = 22 to_port = 22 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 = "bastion_sg" } }
create a security group between bastion host sg and sql sg for connection between them:
resource "aws_security_group" "sqlconnectivitysg" { name = "sqlconnectivitysg" description = "Security Group for Bastion Instance and SQL connectivity" vpc_id = "${aws_vpc.task4_vpc.id}" ingress { description = "SSH Protocol" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_groups=["${aws_security_group.bastionsg.id}"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "sqlconnectivity_sg" } }
Here we have created a security group for SSH connection,when ever a user other than bastion tries to connect with sql by using SSH it check whether it has same security group as bastion only then it connects,so only bastion user can connect to out SQL Database,other than that no other user can connecct,which makes sql isolated and secure
step 5:
create an Elastic IP to be used for nat gateway:
resource "aws_eip" "task4_eip"{ vpc= true }
create an nat gateway by using aws_nat_gateway resource:
Create a NAT gateway for connect our VPC/Network to the internet world and attach this gateway to our VPC in the public network
resource "aws_nat_gateway" "task4_ng"{ allocation_id= "${aws_eip.task4_eip.id}" subnet_id= "${aws_subnet.public_subnet.id}" tags = { Name = "task4_ng" } }
step 6:
Now,we update the routing table of the private subnet, so that to access the internet it uses the nat gateway created in the public subnet
resource "aws_route_table" "task4_routetable_2" { vpc_id = "${aws_vpc.task4_vpc.id}" route { cidr_block = "0.0.0.0/0" nat_gateway_id = "${aws_nat_gateway.task4_ng.id}" } tags = { Name = "task4_routetable_2" } } resource "aws_route_table_association" "task4_route_private"{ subnet_id= aws_subnet.private_subnet.id route_table_id = "${aws_route_table.task4_routetable_2.id}" }
step 7:
Now,we create an instance for wordpress,you can use any ami you want for this:
creating aws instance for wordpress:
resource "aws_instance" "wordpress_os"{ ami= "ami-000cbce3e1b899ebd" instance_type= "t2.micro" subnet_id= "${aws_subnet.public_subnet.id}" vpc_security_group_ids= ["${aws_security_group.wordpresssg.id}"] key_name= "mytask4key" tags = { Name = "wordpress_os" } }
then select any ami for SQL and create an instance:
creating instance for sql:
resource "aws_instance" "sql_os"{ ami = "ami-08706cb5f68222d09" instance_type= "t2.micro" subnet_id= "${aws_subnet.private_subnet.id}" vpc_security_group_ids=["${aws_security_group.SQLsg.id}","${aws_security_group.sqlconnectivitysg.id}"] key_name= "mytask4key" tags = { Name="sql_os" } }
here,I have attached multiple security groups to my SQL instance,one for SQL database connectivity another for the connection of bastion user
creating an instance for Bastion os:
resource "aws_instance" "bastion_os"{ ami = "ami-0732b62d310b80e97" instance_type="t2.micro" subnet_id= "${aws_subnet.public_subnet.id}" vpc_security_group_ids= ["${aws_security_group.bastionsg.id}"] key_name="mytask4key" tags={ Name= " bastion_os" } }
creating output to retrieve IP using terraform:
output "mywordpressos_ip" { value = aws_instance.wordpress_os.public_ip } output "mysqlOSPrivate_ip" { value = aws_instance.sql_os.private_ip } output "bastionos_ip" { value = aws_instance.bastion_os.public_ip }
step 8:
save the terraform file,initialise the terraform using terraform init command and validate the code we have written by using terraform validate command
Now create the infrastructure using terraform apply -auto-approve command:
You can see check from aws web UI that the resources we wanted to create have been created:
Now,use the wordpress IP to open the wordpress site:
step 9:
Now,we connect wordpress instance and check whether nat gateway works or not:
use this command for login to wordpress:
ssh bitnami@<public IP of wordpressinstance> -i mytask4key.pem
we can ping to google!!!!
So our instance can successfully connect to the internet
Now,we check whether we can connect to SQL by using bastion user or not:
For connection to sql inside bastion we need the key we created, for that first connect to bastion os using ssh,than by using winscp or any other way we can transfer our key to bastion os,for that create a .ppk key and connect and copy by using putty connection of winscp,here I have used git hub to copy:
We can also see that by using bastion we can also ping to google,so we can access internet by using it.
Now,we have copied the key inside our bastion host OS,now we try to connect to SQL database instance:
It shows unprotected file due to its permisions any one can access it and change it,due to which it is not secure,so,we use chmod command to change the key's permission:
As you can see we have connected to SQL database which is inside a private subnet by using bastion host.
If you follow the steps I have mentioned you can also create an inrastructure like this easily by using terraform
Github Link : https://github.com/Pheonix-reaper/Task4_Cloud