AWS Three-Tier Architecture: Practical Implementation and Strategies for Secure Private Instance Access
Tags: aws, cloudcomputing, ec2
Published: 2024-07-02 03:50:54

**Introduction**

Creating a three-tier architecture on AWS is an essential skill for any cloud professional. This architecture involves the separation of presentation, application, and data layers to enhance security, manageability, and scalability. Here’s a detailed guide to designing and configuring this architecture, with practical insights and interesting facts along the way.

**Project Overview**

A three-tier architecture consists of:
1. Presentation Tier: The web server that handles the user interface.
2. Application Tier: The app server that processes business logic.
3. Data Tier: The database server that stores and manages data.

**Step-by-Step Guide to Creating the Three-Tier Architecture**

**_1. Setting Up the VPC and Subnets_**

**Why is a VPC important in AWS architecture?**
A Virtual Private Cloud (VPC) allows you to provision a logically isolated section of the AWS cloud where you can launch AWS resources in a virtual network that you define. It gives you complete control over your network settings.

**Create a VPC:**
VPC CIDR: 10.0.0.0/20

**Create Subnets:**
Public Subnet (AZ1): 10.0.0.0/24 (For Bastion Host and Web server)
_Note : Enable auto assign public ip for Public subnets_
Private Subnet 1 (AZ1): 10.0.1.0/24 (For App server )
Private Subnet 2 (AZ1): 10.0.2.0/24 (For Database Server) 
Private Subnet 3 (AZ2): 10.0.3.0/24 (For High availability App Server)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bphchi9v58o6chtsetmc.png)

**2. Configuring the Internet Gateway and Route Tables**

### Internet Gateway
An Internet Gateway enables communication between instances in your VPC and the internet. It serves as a target for routing internet traffic and supports IPv4 and IPv6. Essential for allowing internet access to your VPC resources.

### Route Table
A Route Table contains rules that determine where network traffic is directed. Each subnet in a VPC must be associated with a route table, controlling the traffic flow within the VPC and to external networks. It enables routing to various destinations including internet gateways.

**Inbound and Outbound Traffic**
_Inbound traffic_ refers to any data packets entering your instance from an external source, such as an SSH connection from your local machine or HTTP requests from users accessing your web application.
_Outbound traffic_ refers to data packets leaving your instance to reach an external destination, such as an HTTP request to an external server for updates.

- Attach the Internet Gateway (IGW) to the VPC.
- Create a public route table** and associate it with the public subnet.
- Add a route in the public route table to direct internet-bound traffic to the IGW.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f7kifw2snrrf9ls802dr.png)

**3. Setting Up the Bastion Host**

What is the purpose of a bastion host in a cloud architecture?
A bastion host acts as a gateway that provides secure access to instances in private subnets. It enhances security by reducing the exposure of your private instances.

- Launch an EC2 instance in the public subnet to act as the bastion host.
- Configure security groups to allow SSH access(port 22),HTTP,HTTPS

- Create a key pair to connect to the bastion host. 
For this project, a PPK key pair was generated to enable connection through the PuTTY terminal.

Context on PEM and PPK:
PEM (Privacy Enhanced Mail): Commonly used in various applications including OpenSSH, but PuTTY cannot directly use PEM files.
PPK (PuTTY Private Key): The format required by PuTTY.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7b91yc4gkjbhg142lrxy.png)

**4. Setting Up the Web Server**

Launch an EC2 instance in the public subnet for the web server.
Install Apache HTTP Server on the instance:(user data)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5u2izkfsb0kvm014ztph.png)
- Configure security groups to allow SSH , HTTP (port 80) and HTTPS (port 443) traffic.

**5. Configuring the Application Server**

How does the application server interact with other components in a three-tier architecture?
The application server processes business logic and communicates with the web server for user requests and with the database server for data retrieval and storage.

- Launch an EC2 instance in the private subnet 1 for the application server.
- Configure security groups to allow SSH access from the bastion host and ICMP from the web server.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhctwwtfof8fqnjqg1p6.png)

**6. Setting Up the Database Server**

- Launch an RDS instance** in private subnet 1 for the database server.
- **Configure security groups** to allow MySQL/Aurora traffic from the application server and bastion host.

1. Create a DB subnet group (RDS > DB Subnet group) and choose relevant VPC and private subnets.
2. Create Databases choosing required engine (Maria DB for this project) and set required user name and password.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49tm57uy6idayvhp2iek.png)

**7. Implementing High Availability**

Why is high availability important in a cloud architecture?
High availability ensures that your applications remain accessible even in the event of hardware or infrastructure failures. This is achieved by distributing resources across multiple availability zones.

- Launch an EC2 instance** in the private subnet 3 (AZ2) to ensure high availability.
- Replicate the setup** of the application server in this instance.

**8. Configuring the NAT Gateway**

NAT Gateway
A NAT (Network Address Translation) Gateway allows instances in a private subnet to connect to the internet or other AWS services while preventing the internet from initiating connections with those instances. This is crucial for downloading updates or software packages securely without exposing your private instances directly to the internet.

Create a NAT Gateway in the public subnet and associate it with an Elastic IP.
_Need for an Elastic IP_
An Elastic IP is required for a NAT Gateway to ensure a consistent public IP address that external servers can recognize. This allows for reliable communication from instances in private subnets to the internet and back.

- **Update the route tables** of the private subnets to direct internet-bound traffic to the NAT Gateway.

**Final Security Group Configurations**

_**Bastion Host Security Group:**_
- Inbound: SSH, HTTPS, HTTP, MySQL/Aurora (DB Security group), ICMP(Web server Security Group)
- Outbound: All traffic

**_Web Server Security Group:_**
- Inbound: HTTP (80), HTTPS (443), SSH (22), ICMP IPV4 (App server Security group)
- Outbound: All traffic

**_Application Server Security Group:_**
- Inbound: SSH from Bastion Host, ICMP from Web Server, MySQL/Aurora from Database Server SG
- Outbound: All traffic

**_Database Server Security Group:_**
- Inbound: MySQL/Aurora from Application Server and Bastion Host
- Outbound: All traffic

**_Testing and Verification_**
Note : In few of the commands provided the text requires the user to replace with their relevant content.
**Step1** Connect to the Bastion Host using PuTTY.
open the Putty terminal > Enter the host ip (public ip of Bastion host) > load the credentials (ppk file for Bastion host keypair)> set the time interval for the session in seconds > open

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/29l2uv1qiir3hbawsvcg.png)

**Step2** SSH into the Application Server from the Bastion Host:
Here let us explore about various ways of accessing a private instance in the following sections categorized as Methods 1,2,3 and 4.

**Method 1: Securely Copying Key Files to Bastion Host from Local Machine**
This method involves transferring your private key file to the bastion host, which is then used to SSH into the private instance.

a) Connect to the bastion host as in the previous step and ensure that the instance is up and running.

b) Use the below command on your local computer to copy the key files .

command prompt from local computer >pscp -i <file path for bastionkey(ppk) on local computer> <file path for appserver(pem) on local computer> ec2-user@bastionhost_publicip:/home/ec2-user/

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbc7nxknusyuuvcd7xrn.png)

c) Check if the files are transferred using ls command on bastion host terminal. If successfully done you can get the output as below :

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4hl65roo60ws5o60atb.png)

d) Change permissions of the file so that it can be read prior to establishing a connection with the app server.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gliff0uh0in8gbmray3y.png)

e) SSH into your app server from bastion host using the command below :

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36th37almq893ern5209.png)

If successfully connected to app server via bastion host you will get to see as below : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xfxhpwepqdw4p9379r8e.png)
 
**Step3** Connect to the Database Server from the Application Server:
a) The first step is to install all required packages to connect with MariaDB. 
_I struggled a bit to figure the issue in connecting the DB server and finally it got resolved when all required packages are installed as in the document._
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ConnectToMariaDBInstance.html
sudo dnf install mariadb105
sudo yum install mariadb
apt-get install mariadb-client
mysql --version

b) After updating the packages use the below command to login to DB server with the user name and password provided during the DB instance setup.
mysql -user=<username> -password=<your_password> -host=<database-server-endpoint>
A successful login to DB server will lead to a screen as below where you can provide the command _show databases;_

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ohx1fo949to8ttny9lv.png)

**Method 2: Using Agent Forwarding**
Agent forwarding allows you to forward your SSH credentials from your local machine to the bastion host, eliminating the need to copy private keys.
**Step 1 : Load SSH Keys into Pageant:**

Right-click on the Pageant icon in the system tray.
Select "Add Key" from the context menu.
Navigate to the location of your private key file (e.g., bastionkey.ppk) and select it.
Repeat the process if you need to add multiple keys (e.g., appkeypair.ppk).
Verify Loaded Keys:
Select "View Keys". This will display a list of currently loaded keys.
Below is the image of key listing 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lwh0d8e2igvt18psiv01.png)

**Step 2: Enable Agent Forwarding in PuTTY**
Open PuTTY Configuration:

_Session Configuration:_
In the "Host Name (or IP address)" field, enter the bastion host's public IP address.
_Enable Agent Forwarding:_
In the left-hand menu, navigate to Connection > SSH > Auth.
Check the box that says "Allow agent forwarding". Refer to below pic.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n428m7qaheoiegs5bbka.png)
_Load the Private Key:_
Still in the Connection > SSH > Auth menu, under "Private key file for authentication", click "Browse" and select your bastionkey.ppk file.
Click "Open" to connect.
_SSH from the Bastion Host to the Private Instance_
Verify SSH Agent is Running:
On the bastion host terminal, run:
sh
ssh-add -l
This should list the keys loaded by Pageant.

SSH into the Private Instance:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08jiennxcnziu65lhqqn.png)

On successful connection the app server will be connected via Bastion host.
The crucial part of agent forwarding is that your private key remains on your local machine and is managed by Pageant. The bastion host uses the forwarded key for authentication, which means the key is not physically copied or stored on the bastion host. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ybhzajvkkyyv8bpt5k2.png)

**Method 3: Using Port Forwarding / Tunneling**
_**content to be updated**_
Port forwarding, or tunneling, allows you to create a secure tunnel through the bastion host to the private instance.
It a method of securely sending data through a public network by Encapsulation - wrapping the original data packets inside another set of packets. 
This creates a secure "tunnel" that hides the data from anyone intercepting the traffic.

Technical Steps with PuTTY
_Open First PuTTY Session:_
Connect to the bastion host.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ssijd6gqr4c7u4sfc1i.png)

Enable SSH tunneling: In PuTTY, under Connection > SSH > Tunnels, add a new forwarded port:
Source port: 8888 (or any available local port).
Destination: private-instance-ip:22.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/655e4irjnjf7uatyuo4x.png)

Open by authenticate with the bastion host's credentials (ppk).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9i9n8do7i07gy4idaafh.png)

_Open Second PuTTY Session:_
Connect to localhost:8888.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jeixhwqes8n064k6n6vt.png)

Authenticate with the private instance’s credentials (ppk).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72ktxwjx8x51aj50kvyk.png)

This results in connection to Bastion host and then to App server through tunnel as in below pic.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6m3rzko2elpdfrb9y75.png)

**Method 4: Using EC2 Instance connect Endpoint**
_**content to be updated : This is yet to be experimented and the results will be updated once done**_
Below AWS document has provided clear steps to create EC2 endpoint and using it to connect to the private instance.
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-using-eice.html

Following one of these 4 methods leads to accessing the app server that resides in a private subnet. Further connecting to other server from App server pretty much follow the same steps as in Method 1 except for few relevant selections for ports pertaining to Databases. 

Each method brings unique merits and demerits concerning security, convenience, versatility, and setup complexity. Therefore, selecting the most suitable method requires a thoughtful approach tailored to the specific requirements of your project.

**Conclusion**

This guide provides a comprehensive approach to designing and configuring a three-tier architecture on AWS and focuses on various methods of accessing a private server. The project covers essential aspects of VPC configurations, subnetting, security group settings and secure accessing making it a quick reference for anyone with basic to medium level understanding and looking to build a 3 tier secure architecture in AWS.

**References**
https://aws.amazon.com/blogs/database/securely-connect-to-an-amazon-rds-or-amazon-ec2-database-instance-remotely-with-your-preferred-gui/
https://www.ssh.com/academy/ssh/tunneling
https://medium.com/adessoturkey/how-to-connect-to-private-ec2-instance-database-via-bastion-host-5b05a256f9f7