aws solutions architect project on security pillar - part 1

AWS Solutions Architect Project (Security Pillar) – Secure Application Deployment – Part 1

As part of the Well-Architected Framework from AWS, security is one of the main fundamental aspects in designing and delivering any AWS project. In this project we will demonstrate how to transform a vulnerable cloud environment into a secure and production grade architecture. After deploying the insecure baseline, the step-by-step re-design will follow the security-first design principles by involving the AWS services such as custom VPC, secured EC2, RDS, S3, CloudFront, and ALB (Application Load Balancer) with WAF protection enabled.

To start of with, here is the to-be architecture diagram for this project:

Below is the explanation of above architecture diagram:

  1. The user make the request to the application via HTTPS
  2. AWS WAF filters the requests for common threat
  3. ALB forwards cleaned and filtered request to EC2 instance
  4. EC2 runs the backend apps and gets data from RDS
  5. NAT gateway allows EC2 to access the internet for updates
  6. Bastion host allows a secure SSH connection to EC2
  7. Internet gateway connects public subnet with the internet

Step 1: Insecure Setup – Launch an EC2 Instance with Public Access

  • Go to the EC2 Dashboard, click Launch Instance
    • Name: shoppingcart-app
    • AMI: Amazon Linux 2 or Amazon Linux 2023 (both supported)
    • Instance type: t2.micro (Free Tier eligible)

  • Key pair: Create and download a new key pair (.pem file) for SSH access
  • Network settings:
    • VPC: Use the default VPC
    • Auto-assign public IP: Enable this option
  • Security Group settings – Add these inbound rules:

Step 2: Insecure Setup – Install Node.js and Run the Application

We are simulating a web application deployment where the servers were setup without proper security

Connect to EC2 instance with the .pem key

ssh -i your-key.pem ec2-user@<your-ec2-public-ip>

and then install Node.js using nvm

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
export NVM_DIR="$HOME/.nvm"
source "$NVM_DIR/nvm.sh"
nvm install 24
nvm use 24

Create the Shopping Cart application

mkdir shoppingcart && cd shoppingcart
mkdir public

cat <<EOF > public/index.html
<!DOCTYPE html>
<html>
<head><title>ShoppingCart</title></head>
<body><h1>Welcome to ShoppingCart</h1><p>This is the insecure Demo Page</p></body>
</html>
EOF

cat <<EOF > server.js
const http = require('http');
const fs = require('fs');
const path = require('path');
const server = http.createServer((req, res) => {
  const filePath = path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url);
  fs.readFile(filePath, (err, content) => {
    if (err) {
      res.writeHead(404); res.end('Not Found');
    } else {
      res.writeHead(200); res.end(content);
    }
  });
});
server.listen(80);
EOF

Get the full path to Node.js and copy the output

[ec2-user@ip-172-31-18-36 shoppingcart]$ which node
~/.nvm/versions/node/v24.16.0/bin/node

Start the application

# Get the full path to Node.js
which node

# Copy the output path (e.g., /home/ec2-ser/.nvm/versions/node/v24.16.0/bin/node) Please adjust the node version on your own installation

# Start the server using the full path (& makes sure the task runs on background to keep terminal functional for operations)
sudo /home/ec2-user/.nvm/versions/node/v24.16.0/bin/node server.js &

Test the application by opening it using the EC2 instance public IP

Step 3: Insecure Setup – Deploy a Public RDS Instance

Again, we are simulating the most common miss-configuration in deploying database service which makes it publicly exposed to the public internet due to initially deployment for quick access.

  • Go to Aurora and RDS Dashboard, click Create Database
  • Choose Easy Create and change the value later after database launched
  • Engine options:
    • Creation method: Standard Create
    • Engine: MySQL
    • Template: Free Tier

  • Settings:
    • DB instance identifier: shoppingcart-db
    • Master username: admin
    • Set a simple password (for example, Secret123!)
  • Connectivity (Here is where the critical security issues are happening):
    • VPC: Default VPC
    • Public access: YES (Major vulnerability – never do this in production)
    • VPC security group: Create new or use existing

Security Group Configuration on EC2:

  • Edit the security group to add:
  • Inbound rule: MySQL/Aurora (port 3306) from 0.0.0.0/0

Step 4: Insecure Setup – Create Public S3 Bucket

In here, we are demonstrating how S3 bucket miss-configuration can lead to accidentally sensitive data to be exposed.

  • Go to S3 Dashboard, click Create Bucket
    • Name the bucket: shoppingcart-insecure-demo. (Ensure the name has to be globally unique)
    • Choose the same region as your EC2 instance.
  • Under Block Public Access settings:
    • Uncheck Block all public access
    • Acknowledge the warning prompt

Click Create Bucket

  • Upload a Sample File
    • Click into your newly created bucket → Upload tab
    • Upload a sample file, such as shoppingcart-logo.png, and click Upload
  • Apply Dangerous Bucket Policy
    • Go to the Permissions tab of the bucket.
    • Scroll to Bucket Policy → click Edit
    • Paste the following policy and save (Modify the resource value accordingly to your bucket name):
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowPublicReadAccessToObjects",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::shoppingcart-insecure-demo/*"
    }
  ]
}

This allows all users (even unauthenticated) to read any object in this bucket.

  • Verify Public Access
    • Go back to the uploaded object (shoppingcart-logo.png)
    • Copy the Object URL (visible at the top)
  • Open it in an incognito/private browser window
  • The file should be accessible without any authentication via below URL:
https://shoppingcart-insecure-demo.s3.us-east-1.amazonaws.com/shoppingcart-logo.png

Summary

At this point, we have successfully deployed a highly insecure cloud environment that mimics common real-world issues and vulnerabilities as below list:

  • Network Security Issues
    • No network segmentation between tiers
    • All resources deployed in the public subnets
    • Overly permissive security groups
  • Data Protection Failures
    • Database exposed to public internet
    • No encryption for data at rest or in transit
    • Publicly accessible file storage
  • Access Control Problems
    • SSH access is allowed from anywhere
    • Database is accessible globally
    • No IAM role-based access controls
  • Monitoring and Compliance Gaps
    • No logging or monitoring configured
    • No threat detection enabled
    • No compliance tracking

In part 2, we’ll systematically address each of these vulnerabilities using AWS security best practices, transforming this insecure setup into a production-ready with the proper secure architecture best practices.