AWS 3 Tier Architecture — How to Create a Highly Available, Scalable and Secure Solution
Introduction
A 3 Tier architecture is a popular approach for building web applications because it separates various functions into distinct layers, resulting in better scalability, security, and fault tolerance.
The 3 Tier architecture separates Web, Application, and Database Tiers, with each layer responsible for a specific function. The Web Tier is responsible for serving static content and processing incoming requests, the Application Tier handles application logic and processing, while the Database Tier is responsible for storing and retrieving data.
Knowing how to design and implement a 3 Tier architecture is a valuable skill that can open up various opportunities in the IT industry. It can help you stand out in job interviews, improve project management skills, and develop a deeper understanding of AWS services.
By following this tutorial, you will learn how to design and create a 3 Tier architecture that provides high availability, scalability, and security for your company’s new web application.
Pre-requisites
- A non-root AWS IAM account with enough rights to perform the required actions. It is considered bad practise (and a security risk) to use your root account for daily administrative tasks.
- Some knowledge of AWS services, architecture and networking is useful. Of course, you can pick those skills up by reading my previous articles! 😉
- As the architecture you design gets more complex, it’s a good idea to plan it out in whatever format suits you best. For instance, in this case, I saved my subnet names, CIDR blocks and Availability Zones in a text file so I could refer to it as I was performing this task, making sure I made the correct associations.
The Challenge!
Scenario
You have been asked to design and create a highly available 3 Tier architecture for your company’s new web application. Each tier should be configured as follows:
Web Tier:
- 2 public subnets.
- Minimum of 2 EC2 instances with an OS of your choice (free tier) in an Auto Scaling Group.
- EC2 Web Server Security Group allowing inbound permission from the internet.
- Boot strap static web page or create a custom AMI that already includes the static web page.
- Create a public route table and associate the 2 public subnets.
Application Tier:
- 2 private subnets.
- Minimum of 2 EC2 instances with an OS of your choice (free tier) in an Auto Scaling Group.
- EC2 Application Server Security Group allowing inbound permission from the Web Server Security Group.
- Associate with private route table.
Note: This is not a true application tier as we don’t have any provided code to run on the EC2 instances.
Database Tier:
- Use a free Tier MySQL RDS Database.
- The Database Security Group should allow inbound traffic for MySQL from the Application Server Security Group.
- 2 private subnets.
- Associate with private route table.
Note: No need to use Multi-AZ but be sure to document how you would add it - Remember that when diagramming this tier you are only creating one RDS instance in one subnet even though you are creating two subnets. If you use multi-az or a read replica then and only then should you have a second instance. Make sure to label accordingly.
Considerations:
- You will need to configure a public route table along with private route tables.
- You will need a Nat Gateway in one of your public subnets to allow your instances in private subnets to update packages and patches. Make sure to include this in the private route table.
- In order to reach your EC2 instances in the private subnets, you will either need a bastion host in the public subnet or need to use SSM. You will need to research into both to see which works better for your use case.
- Plan out your CIDRs before you create your VPC and Subnets.
Basic Infrastructure and Web Tier
The first thing we need to do is head over to the VPC dashboard in the AWS Console and click Create VPC.
We’ll choose the VPC only option as we have defined our own architecture and want to have control over all our components.
Input a Name tag and an IPv4 CIDR block range. Click Create VPC.
Success. Now we need to create an Internet gateway so our VPC can access the internet.
Go back to the VPC dashboard and press Internet gateways on the left side menu and then press the orange Create internet gateway button.
Input a Name tag and click the Create internet gateway button.
If successful, click Attach to a VPC button on the top right of the screen.
When you click in the Available VPCs field, you should be able to select the VPC you just created from a drop down list. So select your VPC and press the Attach internet gateway button.
Once that’s successful, we can move on to creating our subnets.
Again, go back to the VPC dashboard, this time click Subnets from the left hand menu and click Create subnets.
Ignore any existing subnets listed as we are going to create new ones for this exercise.
Click in the VPC ID field and select your required VPC from the drop down menu.
The eagle eyed reader might notice that the screenshot shows the initial setup of my VPC had a CIDR block range of 10.0.0.0/24. Well, it turns out that wasn’t a large enough range to handle all my subnets, so I had to delete the VPC and start again.
What was that I said about planning? 😋
Next, enter the first subnet details. This is our first public subnet. Click Add new subnet.
Add our second public subnet. Note the different Availability Zone.
Click Add new subnet again and repeat the process for the rest of our subnets.
Once your final subnet details are entered, click the Create subnet button.
Success. Now we are ready to create a route table for our public subnets.
Return to the VPC dashboard, click Route tables from the left hand menu and click Create route table button.
Input a Name and select your VPC from the drop down menu. Click Create route table.
Success.
Click the Edit routes button on the lower portion of the screen.
You will have a default route in place. Click Add route.
Select 0.0.0.0/0 as your Destination, choose Internet Gateway in the Target field and then select the internet gateway you created when it appears in the menu. Click Save changes.
Once the new route is in place, click the Subnet associations tab.
In the Explicit subnet associations box, press the Edit subnet associations button.
Select our two public subnets and click Save associations.
That’s now the basic infrastructure set up for the public components of our architecture, so we can move on to setting up our public EC2 instances.
This time, navigate to the EC2 Dashboard, click Security Groups from the left hand menu and click the Create security group button.
Input a Security group name, a Description and double check the correct VPC is selected by clicking in the VPC field.
Press the Add rule button.
We’re adding SSH for admin access, HTTP to allow our web site to display and HTTPS for SSM access as it uses port 443.
AWS SSM is a tool that helps you manage and automate tasks across your AWS resources. It simplifies operational tasks — such as patching and maintaining instances or running scripts — and helps reduce manual intervention, allowing you to manage your resources more efficiently.
No other changes required, so click Create security group.
Success. Now let’s go to the IAM Dashboard as we need to create a role that give SSM permissions to access our EC2 instances.
On the IAM Dashboard, click Roles on the left hand menu and then click the Create role button.
Check AWS service and check EC2 under Common use cases. Click Next.
I searched for SSM and have checked the policy highlighted as the Description confirms this is what we want.
Click Next at the bottom of the screen.
Input a Role name and then click the Create role button at the bottom of the screen.
Once the role is successfully created, head back to the EC2 Dashboard.
Click Launch templates from the left hand menu and then click the Create launch template button.
Enter Launch template name and Template version description. Check Auto Scaling guidance.
Choose a free tier Amazon Linux 2 AMI.
Select t2.micro as your Instance type and I’m just using an existing Key pair, but you can generate a new pair if needed.
On the Network settings section, ensure Select existing security group is selected, then click the Common security groups drop down and select your previously created Web Tier security group.
Click to open the Advanced network configuration options and add a Network interface, then set Auto-assign public IP to Enable.
We’re not going to change Storage or Tags for this exercise, so skip to the Advanced details section, expand it and select the role we created earlier from the IAM instance profile drop down.
Scroll down to the User data section and paste in the code shown.
I will put the whole script in a code box at the end of the document. It will install Apache web server, set up a basic website and install and start the SSM agent.
Click Create launch template.
Success. Now, let’s head back to the EC2 Dashboard.
Click Auto Scaling Groups from the left hand menu, then click the Create Auto Scaling group on the top right of the screen.
Input an Auto Scaling group name…
…then select the Launch template you created from the drop down menu. Click Next.
Select the correct VPC from the drop down menu and select the correct public subnets from the Availability Zones and subnets menu.
Click Next.
We want to Attach to a new load balancer and as this stage is for our web traffic, we’ll choose an Application Load Balancer that is Internet-facing.
Under Default routing (forward to), click the drop down menu and select Create a target group. It will auto populate a name, but you may need to change it to something more appropriate.
You can check any required Health checks and Monitoring options and then click Next.
Set the parameters of our Auto Scaling group…
…then click Next.
Click Next.
Click Next.
Check everything on the Review page and if it’s all correct, click Create Auto Scaling group.
Looks good, so let’s go to the EC2 Dashboard once again and check our newly spun up instances.
If we take one of the public IP addresses…
…and put it into a browser on our workstation — success! Our EC2 instance is configured correctly and displays our basic website.
Application Tier
This tier is very similar to the Web Tier in structure, but there are different security requirements. Additionally, we need to create a NAT gateway.
In essence, the NAT gateway allows resources in a private network to communicate with the outside world while maintaining a secure environment.
Therefore, through the NAT gateway, resources in our private subnets can access the internet in a secure manner.
Head back to the VPC Dashboard, click NAT gateways from the left hand menu and click Create Nat gateway button on the right of the screen.
Input a Name, select one of the public subnets you created earlier from the Subnet drop down menu and click the Allocate Elastic IP button to set an Elastic IP allocation ID.
By assigning an Elastic IP address to your NAT Gateway, you provide it with a static public IP address that doesn’t change, even if the NAT Gateway is stopped and started again.
This is important because any change to the NAT Gateway’s public IP address can break connectivity between your resources in the private subnet and the internet.
Click Create NAT gateway.
Success. Now we need to set up routing for our Application Tier.
On the VPC Dashboard, click Route tables from the left hand menu and then click the Create route tables button.
As before, enter a Name, select the correct VPC from the drop down menu and click Create route table.
Click Edit routes button in the Routes section.
Click Add route.
Select 0.0.0.0/0 as the Destination, Select NAT Gateway from the Target drop down menu and select the NAT gateway you created. Click Save changes.
Still on your private route table page, select the Subnet associations tab and click Edit subnet associations in the Explicit subnet associations section.
Check the two private subnets we allocated for the Application Tier and click Save associations.
Now we need a Security Group for our private subnets that will only allow traffic from our Web Tier Security Group.
From the VPC Dashboard, click Security Groups on the left hand menu and click the Create security group button.
Input a Security group name, Description and be sure to select the correct VPC.
Click Add rule in the Inbound rules section. Here we are creating rules for SSH, HTTP and HTTPS again, but we are also adding All ICMP IPv4.
The latter will allow us to ping from EC2 instances in our public subnets to the instances in our private subnets and verify they can communicate.
Note that for our Source field, we select Custom and when we click in the search field, we can select our Web Tier Security Group from a drop down list.
Click Create security group.
Once it’s successfully created, we need to create a Launch Template for our Application Tier that uses that Security Group.
Go back to the EC2 Dashboard, select Launch Templates from the left hand menu and click Create Launch template button.
Most of the configuration is the same as before, but note our new Security Group selected.
Also don’t forget to set Auto-assign public IP to Enable!
Set the SSM role in the Advanced details section again.
Add the same script into the User data section — although we don’t really need to install Apache and set up a web site this time — it’s more for installing the SSM agent.
Click Create launch template.
Success, so now let’s create another Auto Scaling Group for this tier.
Once again, back to the EC2 Dashboard, click Auto Scaling Groups from the left hand menu, then click the Create Auto Scaling group on the top right of the screen.
Input an Auto Scaling group name and select our Application Tier Launch template from the drop down menu.
Click Next.
Select the correct VPC from the drop down menu and our two Application Tier private subnets.
Click Next.
Attach to a new load balancer. Again this will be an Application Load Balancer, but this time Internal.
Create a New target group name. (Edit — I actually had to shorten the name in the screenshot as it was over the allowed character length!).
Select required Health checks and Additional settings and click Next.
Set the required Group size parameters and click Next.
Click Next on Add notifications and Add tags screens.
If everything looks good on the Review screen, click Create Auto Scaling group.
If we check our running instances, we can see 4 available.
Now we need to check that the Web Tier instances can ping the Application Tier instances.
Let’s SSH into the Web Tier server we checked before on IP 3.8.82.17.
Aaaannndd pinging to an EC2 instance in a private subnet doesn’t work. Of course!
Well, it was nearly 1am while I was writing this — I was tired, what can I say? After about 20 minutes of cursing, I remembered I was supposed to be pinging the private IP address of the instance in the private subnet. Arg — I’d been trying to ping the public IP address!
Ok, let’s ping 10.0.4.83 from our Web Tier instance…
Success! Now we can move onto the final stage and create our Database Tier.
Database Tier
Let’s create our Database Tier Security Group first.
Go to the EC2 Dashboard, click Security Groups from the left hand menu and press the Create security group button.
Input Security group name, Description and choose the correct VPC.
In the Inbound rules section, click Add rule. Select MYSQL/Aurora, choose Custom Source and select your Application Tier Security Group.
Click Create security group button.
Success, so let’s create our database now.
Search for rds in the search bar if you don’t already have a shortcut set up. Click RDS under the returned Services.
Click Create database.
Check Standard create and MySQL.
Check Free tier.
Choose a DB instance identifier and set your database username and password. I am keeping things very simple here.
Don’t connect to an EC2 compute resource and select the correct VPC.
Hmm, looks like I need to create a new DB Subnet Group.
Open up another tab for the AWS Console, go to the RDS Dashboard, click Subnet groups on the left hand menu and press Create DB subnet group.
Enter a Name, Description and as ever, choose the correct VPC.
Select your Database Tier private subnets and your last remaining CIDR blocks, then click Create.
Success. Now let’s go back to our database configuration.
Ugh, I had to start the database creation from scratch. Now my newly created DB subnet group is auto selected when I select my VPC.
Select your Application Tier security group from the Existing VPC security groups menu. You may need to remove the Default security group too.
That’s all the customisation required, so click the Create database button at the bottom of the screen.
That took quite a while! But our database is up and configured and available, so we have completed our 3 Tier environment.
The only thing left to check is if our SSM setup is working.
Type ssm in the Search field and click Systems Manager under the returned Services.
Click Inventory on the left hand menu.
I was hoping that this would be working straight off the bat since we installed the agent via our Bash script as part of our Launch Templates.
However, let’s Click here to enable inventory on all instances.
Click View detail.
After a couple of minutes, all our instances are successfully associated.
If we click Fleet Manager from the left hand menu, we get a bit more detail, including confirmation that the SSM Agent is responding on all instances.
I’m happy that this task is successfully complete, so now the most important part — tear everything down so we don’t get charged!
NAT gateways, Elastic IPs and Application Load Balancers incur a small charge, so we don’t want to leave them running.
Conclusion
Wow, the complexity went up a notch with this exercise and I was up into the wee small hours to get this task complete.
I’m glad I got there in the end and I hope this is a useful resource for anyone taking the time to read. If this has helped, I’d really appreciate a clap or comment.
One final tip — I’m not the biggest fan of drawing architecture diagrams, but I have to say https://lucid.app/ is one of the best tools I have used for this purpose. It’s intuitive and unlike other tools I’ve used, the arrows are easy to place and your objects don’t jump around all over the place! Well worth checking out even though you need to sign up for it.
As always, feel free to reach out to me with any questions and take care dear reader!
Bash Script to set up an Apache Server, set up a basic web site and install the SSM Agent
As promised, here is the full script I used. It’s based on a script I have used in a number of my previous articles, so will look familiar!
#!/bin/bash
# update all packages on the server
yum update -y
# install apache http web server
yum install -y httpd
# install firewalld to allow use of firewall-cmd
yum install -y firewalld
# enable and start apache web server. also ensure it starts automatically after a reboot
systemctl enable --now httpd
# enable firewall
systemctl enable --now firewalld
# add http service to firewall and restart to apply change
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --reload
# check for the directory /var/www/html and create it if it does not exist
if [ ! -d "/var/www/html" ]; then
mkdir -p /var/www/html
fi
# download a royalty free landscape image and move it to /var/www/html
wget -O /var/www/html/bg.jpg https://mdbootstrap.com/img/Photos/Horizontal/Nature/full%20page/img%20%283%29.jpg
# create a new index.html file and add content
echo "<html>" > /var/www/html/index.html
echo "<head>" >> /var/www/html/index.html
echo "<title>Level Up In Tech - Project 8 - John MacLean</title>" >> /var/www/html/index.html
echo "<style>" >> /var/www/html/index.html
echo "body { background-image: url('bg.jpg'); background-size: cover; text-align: center; }" >> /var/www/html/index.html
echo "</style>" >> /var/www/html/index.html
echo "</head>" >> /var/www/html/index.html
echo "<body>" >> /var/www/html/index.html
echo "<h1>LUIT - Gold Team - DevOps - January 2023 cohort. This is the AWS Tier 3 Project!</h1>" >> /var/www/html/index.html
echo "</body>" >> /var/www/html/index.html
echo "</html>" >> /var/www/html/index.html
# install SSM agent
yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
systemctl start amazon-ssm-agent
systemctl enable amazon-ssm-agent
The script is designed to be used on an Amazon Linux 2 AMI and used in the User data section of a Launch Template. Scripts run from there are run as root, hence no sudo commands are in the script.
Happy coding!