Back to Work

AWS Cloud
Project

AWS Networking Cybersecurity

A secure, scalable, and highly available cloud environment designed to host a public web application across multiple Availability Zones, utilizing a decoupled two-tier architecture.

Conceptual 2-tier architecture diagram

Fig 1. Two-Tier Cloud Architecture Diagram

Subnet Sizing

When designing the Virtual Private Cloud (VPC), subnet sizing was carefully planned to balance efficiency, scalability, and security. We adhered to the "Rule of Thirds," ensuring sufficient IP address capacity for immediate needs while allowing room for growth and unexpected expansion.

We allocated large subnets first for optimal efficiency, keeping in mind that AWS reserves 5 IP addresses per subnet. Crucially, sizing was dictated by the tier's function:

  • Public Subnets: Kept smaller to minimize the potential attack surface.
  • Application (EC2) Private Subnets: Allocated the largest blocks to accommodate dynamic horizontal scaling handled by the Auto Scaling Group.
  • Database Private Subnets: Sized smaller, as databases typically rely more on vertical scaling rather than horizontal expansion.
Load Balancing

To ensure fault tolerance and handle traffic spikes, the web tier is fully decoupled. We deployed an Application Load Balancer (ALB) across two public subnets, which securely distributes incoming HTTP/HTTPS traffic to our private application instances.

The backend EC2 instances are managed by an Auto Scaling Group (ASG). Using target tracking scaling policies, the infrastructure automatically provisions new instances when the average request count per target exceeds a threshold, and terminates them when traffic subsides. To make this "self-healing," I engineered a robust User Data script that automatically installs the PHP environment and syncs the latest application files from an S3 bucket upon boot.

User Data Script

Fig 2. User Data Script for Automated Instance Configuration

DNS & Routing

A critical piece of the networking puzzle was bridging the gap between our AWS infrastructure and the end user gracefully. Rather than exposing the autogenerated, cumbersome AWS Load Balancer URL, I leveraged Cloudflare's DNS management to attach our custom domain.

By configuring a CNAME record to point our subdomain (egl211.rirori.xyz) directly to the Load Balancer, we established a clean, professional entry point. This setup not only improved the user experience but also allowed us to funnel all incoming traffic through Cloudflare's edge network for SSL termination and traffic proxying.

S3 & CORS Challenges

My responsibilities also included engineering the storage architecture. We utilized Amazon S3 for durable, highly available object storage to handle user file uploads. However, decoupling the storage from the compute instances introduced a significant technical hurdle: cross-origin security blocks.

Initially, direct file uploads from the web application failed silently. Because the application was being served via our custom Cloudflare domain, the web browser blocked cross-origin requests to the native AWS S3 endpoint. To resolve this, I had to dive deep into S3 permissions and architect a strict Cross-Origin Resource Sharing (CORS) policy. This policy explicitly allowed PUT and POST methods exclusively from https://egl211.rirori.xyz.

I paired this CORS configuration with a tightly scoped Bucket Policy on our storage bucket (grp2-prod-webapp-uploads-s3), ensuring the principle of least privilege by explicitly defining allowed actions such as s3:PutObject and s3:GetObject.

S3 Bucket Policy JSON
S3 CORS Policy JSON

Figs 3-4. Securing S3 with Strict Bucket & CORS Policies

Zero Trust DNS

A major focus of this project was securing the perimeter. Following the principle of least privilege, I restricted the Load Balancer's security group to only allow traffic from Cloudflare's verified IP ranges. This hides the AWS infrastructure from the open internet and mitigates direct DDoS attacks.

To protect sensitive S3 upload and download functionalities without hardcoding authentication into the backend, I implemented Cloudflare Zero Trust. By setting up an identity-aware proxy, every user is forced to authenticate against a specific GitHub organization before their traffic is even routed to the internal AWS Load Balancer.

Cloudflare DNS Dashboard
Cloudflare Zero Trust Policies

Figs 5-6. Custom DNS & Identity-Aware Proxy Configuration

SSH Security

Because the application and database servers sit inside private subnets without public IPs, direct SSH access is impossible. We deployed a Bastion host in the public subnet to act as a secure jump box.

Instead of leaving sensitive private key files sitting on the Bastion host (a major security risk if the host is compromised), I utilized SSH Agent Forwarding (ssh -A). This protocol allows the local machine's SSH agent to seamlessly authenticate the connection from the Bastion into the private EC2 instances, ensuring the private key never leaves my local device. Furthermore, we hardened the Bastion by installing Fail2ban to immediately ban IPs attempting brute-force attacks.

SSH Agent Forwarding Terminal

Fig 7. Agent Forwarding through the Bastion Host

What I Learned

Serving as the Group Leader for this deployment was a massive exercise in coordination and architectural planning.

Managing a distributed system taught me that consistency is the foundation of security. Moving from manual configurations to automated deployments through the ALB and User Data scripts completely changed how I view infrastructure reliability.

A major technical hurdle I encountered was "session drift." Because the web application initially used local file-based PHP sessions, users frequently got logged out when the Load Balancer routed their subsequent requests to a different EC2 instance. This was a critical architectural lesson: true horizontal scaling requires statelessness. If I were to rebuild this architecture, I would implement a centralized session management system to store session data in a central "Source of Truth" like Redis (ElastiCache) or the RDS database.

Beyond the technical architecture, this project reinforced that team coordination is rarely straightforward. As reflected in the final documentation, compiling our report required me to take ownership of the overall structure, standardizing the styling and formatting across all team members' disparate contributions, and meticulously managing all figure references. It was a practical lesson in how clear communication and consistent documentation standards are just as critical to a successful deployment as the infrastructure itself.