DEV Community

Geovane Oliveira
Geovane Oliveira

Posted on

Protecting an EC2 hosted web application with AWS WAF in practice

Web applications on EC2 are everywhere. And honestly, a lot of them are just sitting there exposed to the internet with nothing more than a Security Group between them and every bot, scanner, and attacker out there.

This article walks through building a straightforward architecture to answer one specific question: How do you protect a web application on EC2 from common web attacks without touching the application code?

We'll use AWS WAF for Layer 7 protection, Security Groups for network control, and AWS Certificate Manager for encrypted transport, all at minimal cost and complexity.

Understanding network layers before adding security controls

Before jumping into AWS services, let's get clear on how network communication actually works. The OSI model helps here, but we'll keep it practical.

Layer 3 – Network layer

Deals with IP addresses. This is about knowing where traffic is coming from and where it's headed.

Layer 4 – Transport layer

Deals with ports and protocols. This controls how connections get established, think TCP on port 80 or 443.

Together, these two layers answer questions like: Who's sending this traffic? Which port are they using? Should this connection even be allowed?

Layer 7 – Application layer

This is where HTTP and HTTPS live. It understands URLs, headers, query strings, request bodies and the actual content of what's being sent.

Layer 7 answers a different kind of question: What is the user actually trying to do?

Here's the thing: most web attacks happen at Layer 7, not at the network level. Understanding this distinction is critical.

What a Security Group is and how it works

Security Groups are probably the first security control you run into in AWS. They're virtual firewalls that control network level access to things like EC2 instances and load balancers.

A Security Group evaluates traffic based on:

  • Source IP address
  • Destination port
  • Protocol

From the OSI perspective, Security Groups operate at Layer 3 (Network) and Layer 4 (Transport).

Key characteristics:

  • Stateful – if traffic is allowed in, the response is automatically allowed out
  • Allow only – you can't write deny rules, only allow rules
  • Everything else is denied by default

Example rules:

  • Allow inbound TCP traffic on port 80 from anywhere (0.0.0.0/0)
  • Allow SSH on port 22 only from your office IP
  • Deny everything else (implicit)

Security Groups are essential. They're your first line of defense.

What Security Groups cannot protect against

But here's the limitation: Security Groups don't understand HTTP or HTTPS content at all.

They can't:

  • Inspect URLs
  • Analyze query strings
  • Detect SQL injection attempts
  • Catch Cross Site Scripting (XSS)
  • Identify malicious payloads in request bodies

From a Security Group's perspective, if port 80 is open and the source IP is allowed, the request gets through no matter what's actually inside that request.

This is a fundamental limitation when you're trying to protect web applications.

Why application layer protection is required

Web attacks are application layer problems. That means you need Layer 7 inspection.

This is where AWS WAF comes in.

AWS WAF is a fully managed Web Application Firewall that inspects HTTP and HTTPS requests before they ever reach your application. It looks at:

  • URL paths
  • Headers
  • Query strings
  • Request bodies

Based on rules you define (or use AWS Managed Rules), it can:

  • Allow requests
  • Block requests
  • Count requests for monitoring

The best part? No agents on your EC2 instances. No changes to your application code.

Why an Application Load Balancer is part of the design:

AWS WAF can't attach directly to an EC2 instance. It needs to be associated with one of these:

  • Application Load Balancer
  • API Gateway
  • CloudFront

For this architecture, the Application Load Balancer serves as:

  • The public entry point
  • The integration point for AWS WAF
  • The boundary between the internet and your compute layer

Even if you're only running a single EC2 instance, this design mirrors what you'd see in production environments.

Architecture overview

The architecture below shows the scenario we are going to discuss in this article.

AWS WAF Architecture Diagram
Figure 1: Conceptual architecture for protecting an EC2-hosted web application using AWS WAF attached to an internet-facing Application Load Balancer

The flow works like this:

  1. Internet traffic hits the Application Load Balancer
  2. AWS WAF inspects HTTP requests at Layer 7
  3. Allowed requests get forwarded to the EC2 instance
  4. Security Groups restrict network level access between components

Architecture components:

Amazon EC2 – Runs a simple Nginx web application in a public subnet

Application Load Balancer – Exposes the application to the internet and routes traffic to EC2

AWS WAF – Inspects and filters HTTP requests before they reach the application

AWS Certificate Manager – Provides free SSL/TLS certificates for HTTPS encryption

Systems Manager Session Manager – Provides secure, SSH free access to EC2 instances via IAM

Auto Scaling Group – Maintains a single EC2 instance (and makes it easy to scale later if needed)

Security Groups – Enforce strict Layer 3 and Layer 4 access rules

Each component protects a specific layer. There's no redundancy or overlap.

Setting up the infrastructure

Let's walk through the key configuration steps. I'll focus on the security specific settings that matter most.

Step 1: Creating the Application Load Balancer

First, we need to set up the ALB that will serve as our public entry point.

ALB Configuration in AWS Console
Figure 2: Application Load Balancer basic configuration

Key settings to configure:

  • Scheme: Internet facing
  • IP address type: IPv4
  • Listeners: HTTP (port 80) and HTTPS (port 443)
  • Availability Zones: Select at least two for high availability

The ALB needs to be in a public subnet since it's receiving traffic directly from the internet.

Step 2: Configuring Security Groups

Security Groups control network level access. We need two distinct groups here.

ALB Security Group:

ALB Security Group Rules
Figure 3: Security Group rules for the Application Load Balancer

Inbound rules:

  • Allow HTTP (port 80) from 0.0.0.0/0
  • Allow HTTPS (port 443) from 0.0.0.0/0

EC2 Security Group:

EC2 Security Group Rules
Figure 4: Security Group rules for the EC2 instance

Inbound rules:

  • Allow HTTP (port 80) only from the ALB Security Group

Note: Unlike traditional setups, we're not opening SSH port 22. Access to the instance for management purposes is handled through AWS Systems Manager Session Manager, which uses IAM authentication and doesn't require any inbound ports to be open.

This is crucial: the EC2 instance never accepts traffic directly from the internet. Only the ALB can reach it on port 80, and administrative access is through SSM Session Manager only.

Step 3: Creating the AWS WAF Web ACL

Now we add the Layer 7 protection. This is where AWS WAF comes in.

AWS WAF Web ACL Configuration
Figure 5: Creating a Web ACL in AWS WAF

When creating the Web ACL:

  • Give it a descriptive name (e.g., ec2-app-protection-waf)
  • Select Application Load Balancer as the resource type
  • Associate it with the ALB you created earlier

Step 4: Adding AWS Managed Rules

Instead of writing custom rules from scratch, we'll use AWS Managed Rule Groups. These are maintained by AWS and updated automatically.

Recommended rule groups to enable:

  • Core rule set (CRS) – Protects against common attacks like OWASP Top 10
  • Known bad inputs – Blocks requests with patterns associated with exploit attempts
  • SQL database – Prevents SQL injection attacks
  • Linux operating system – Blocks requests targeting common Linux vulnerabilities

Each rule group adds a layer of protection. Start with these four since they cover the most common attack vectors.

Step 5: Associating WAF with the ALB

Once the Web ACL is configured, associate it with your Application Load Balancer.

The association happens in one of two ways, depending on where you started the configuration. If you created the Web ACL from the WAF console, you selected the ALB during the initial setup under (Associated AWS resources). If you're adding WAF to an existing ALB, you'll find the option in the Load Balancer console under the (Integrated services) tab.

From the Load Balancer perspective, you'll see a section labeled (AWS WAF) where you can attach a Web ACL. Click "Edit" and select your newly created Web ACL from the dropdown. The attachment is immediate there's no downtime, no need to restart anything.

Once associated, you'll see the Web ACL name displayed in the ALB's integrated services section. You can verify the reverse connection by going back to the WAF console, selecting your Web ACL, and checking the (Associated AWS resources) tab. Your ALB should be listed there.

This is the critical connection point. Every HTTP request hitting your ALB will now pass through AWS WAF inspection before reaching your EC2 instance. The WAF evaluates each request against your rule groups in order of priority, and either allows it through, blocks it with a 403 response, or counts it for monitoring purposes depending on how you've configured each rule.

The inspection happens inline with minimal latency, typically adding only single digit milliseconds to request processing time. If WAF blocks a request, the connection never reaches your application layer. The request is terminated at the ALB with a 403 Forbidden response.

Step 6: Configuring IAM Role for Systems Manager

To enable secure, SSH free access to the EC2 instance, we attach an IAM role that allows Systems Manager Session Manager to function.

IAM Role for SSM
Figure 7: IAM role configuration for Systems Manager access

The IAM role includes the AmazonSSMManagedInstanceCore managed policy, which provides:

  • Permission for the SSM agent to communicate with Systems Manager service
  • Ability to retrieve commands and send outputs
  • CloudWatch Logs integration for session logging (optional but recommended)

Note on SSM Agent: If you're using Amazon Linux 2023 (as in this setup), the SSM agent comes pre installed and enabled by default. For other AMIs like Ubuntu or older Amazon Linux versions, you may need to install the agent manually. The combination of the IAM role and the pre installed agent is what enables Session Manager to work immediately after instance launch.

Once attached, you can access the instance through the AWS console or CLI without opening SSH ports or managing key pairs. All sessions are authenticated through IAM and can be logged for audit purposes.

Step 7: Monitoring and testing

After everything is configured, you can monitor WAF activity through CloudWatch metrics.

AWS WAF provides real time metrics that show how your Web ACL is performing. These metrics are automatically published to CloudWatch and typically appear within 5 to 10 minutes of activity.

Key metrics to watch:

  • AllowedRequests: Legitimate traffic getting through
  • BlockedRequests: Malicious requests stopped by WAF
  • CountedRequests: Requests matching rules in count mode

To view these metrics:

  1. Navigate to the AWS WAF console
  2. Select your Web ACL
  3. Go to the Overview tab
  4. CloudWatch metrics will display showing request patterns over time

You can also view detailed logs in CloudWatch Logs if you enable WAF logging.

Transport security with HTTPS

All traffic between clients and the Application Load Balancer is encrypted using TLS 1.2 or higher. The SSL certificate is provided by AWS Certificate Manager at no cost and renews automatically.

HTTPS Certificate Configuration
Figure 10: SSL/TLS certificate from AWS Certificate Manager

The ALB is configured to:

  • Accept HTTPS connections on port 443 with a valid SSL certificate
  • Redirect all HTTP traffic to HTTPS (301 permanent redirect)
  • Use modern cipher suites (TLS 1.2+ only)
  • Serve a certificate trusted by all major browsers

This ensures that sensitive data cannot be intercepted or read by attackers performing man-in-the-middle attacks. The certificate is issued and managed by AWS Certificate Manager, which handles automatic renewal before expiration.


Video walkthrough: For a complete hands-on demonstration of this setup, check out the video tutorial below where I walk through each step in the AWS console.

[Video soon]


What AWS WAF protects against in practice

Using AWS Managed Rules, AWS WAF can block common attack patterns like:

  • SQL injection attempts
  • Cross-Site Scripting (XSS)
  • Path traversal attacks
  • Malformed or suspicious HTTP requests
  • Basic automated scanners and bots

Important point: AWS WAF doesn't fix insecure code. What it does is reduce your exposure by blocking known malicious patterns before they ever reach your application.

What this architecture does NOT cover (and why it matters)

This architecture provides solid foundational protection with network segmentation, application layer filtering, encrypted transport, and IAM based instance access. However, it's important to understand its limitations. This is a strong starting point that demonstrates core security principles, not a complete enterprise grade solution.

What's missing for a production environment:

Network Isolation:

  • EC2 in public subnet (production should use private subnet, see "Ideal Architecture" below)
  • EC2 has public IP (though no direct access is possible due to Security Groups)
  • No VPC Endpoints for fully isolated SSM access
  • No NAT Gateway for controlled outbound traffic from private instances

Advanced DDoS Protection:

  • No AWS Shield Advanced for sophisticated volumetric attacks
  • No rate based rules in WAF to limit request velocity per IP
  • No geographic restrictions (geo blocking) for region specific threats

Monitoring and Threat Detection:

  • WAF logging disabled (to minimize costs for this demo)
  • No AWS GuardDuty for threat intelligence and anomaly detection
  • No Security Hub for centralized security findings across services
  • No VPC Flow Logs for network traffic analysis
  • No CloudWatch Alarms for proactive alerting on suspicious activity

Identity and Secrets Management:

  • No AWS Secrets Manager for database credentials or API keys
  • Session Manager logging not enabled (optional enhancement)
  • No MFA requirement for Session Manager access

Compliance and Governance:

  • No AWS Config for continuous compliance checking
  • No automated patch management with Systems Manager Patch Manager
  • No backup strategy with AWS Backup
  • No vulnerability scanning with AWS Inspector

Advanced Application Protection:

  • No AWS WAF Bot Control for sophisticated bot mitigation
  • No reCAPTCHA challenges for suspicious activity
  • No account takeover prevention features
  • No fraud detection patterns

Content Delivery:

  • No CloudFront for global edge caching and additional DDoS protection
  • No origin shielding to reduce load on the ALB

Recommendation: For production, place CloudFront in front of the ALB to:

  • Hide the ALB's DNS name from public access
  • Add an additional WAF layer at the edge
  • Improve global performance with caching
  • Protect against DDoS attacks with AWS Shield

Ideal architecture for production:

For production workloads, the recommended architecture would place the EC2 instance in a private subnet with no public IP address and use VPC Interface Endpoints for Systems Manager connectivity. Here's what that would look like:

Enhanced Network Architecture:

Key differences:

  • EC2 in private subnet - No public IP, no direct internet access
  • VPC Interface Endpoints - Enable SSM access without internet gateway (~$21.60/month for 3 endpoints)
  • NAT Gateway - If EC2 needs outbound internet access (~$32.40/month + data transfer)
  • CloudFront - Global distribution and edge protection

Why not include this in the current architecture?

VPC Interface Endpoints cost approximately $0.01/hour per endpoint (~$7.20/month each). For Systems Manager to work in a private subnet, you need 3 endpoints:

  • com.amazonaws.region.ssm
  • com.amazonaws.region.ec2messages
  • com.amazonaws.region.ssmmessages

Total cost: ~$21.60/month just for the VPC Endpoints, plus additional complexity in setup and troubleshooting. For an educational article focused on WAF and application security fundamentals, this additional cost would make the architecture less accessible for learning purposes.

The current implementation keeps the EC2 in a public subnet but eliminates SSH exposure entirely through Systems Manager Session Manager. While the instance has a public IP, the Security Group ensures no direct access is possible, only the ALB can reach it on port 80. This achieves approximately 90% of the security benefit of a private subnet at 0% of the additional cost, making it ideal for learning, development, and testing environments.

Why this matters for your security journey:

This architecture demonstrates Layer 3, 4, and 7 protection fundamentals with encrypted transport, IAM based access control, and zero SSH exposure. It's an excellent educational starting point and works well for:

  • Development and testing environments
  • Learning AWS security concepts and best practices
  • Understanding the defense in depth model
  • Proof of concepts and demos
  • Small internal tools with limited exposure
  • Personal projects and portfolios

However, for production workloads handling real user data, PII, or serving public traffic at scale, you need the additional layers mentioned above. Security is not a single solution, it's a layered approach where each control addresses specific attack vectors and threat models.

Recommended next steps:

  1. Enable Session Manager logging to CloudWatch for audit trails (minimal cost)
  2. Add rate-based rules to WAF for basic request rate limiting
  3. Enable CloudWatch logging for WAF and create alarms for blocked requests
  4. Implement GuardDuty for threat detection ($4-$10/month for light usage)
  5. Use Security Hub for centralized security findings (additional cost)
  6. Evaluate private subnet migration with VPC Endpoints when budget allows
  7. Consider CloudFront for global distribution and additional edge protection
  8. Enable automated patching with Systems Manager Patch Manager

Each of these topics deserves its own deep dive, which I plan to cover in future articles as part of a comprehensive AWS security series.

AWS WAF pricing is based on:

  • Number of Web ACLs
  • Number of rules
  • Number of requests inspected

A few things to know for this setup:

  • AWS WAF is not included in the AWS Free Tier
  • For low traffic environments, costs are typically minimal
  • Costs stay predictable as long as you clean up resources after testing

If you're just experimenting, expect single digit dollar amounts per month for WAF itself, assuming moderate traffic.

Conclusion

Security Groups and AWS WAF aren't competing solutions. They work at different layers and solve different problems.

Security Groups control who can connect.

AWS WAF controls what those connections are trying to do.

Understanding which control applies at which layer is what makes it possible to build secure, scalable architectures, even for relatively simple workloads.

Protecting a web application doesn't require complex tooling. It requires putting the right controls at the right layers.

If you're running web applications on EC2 without WAF, this architecture is a solid starting point.


A note on this content

This article documents my learning journey with AWS security architecture. I'm sharing what I've learned and built, not claiming to be an expert. If you spot something that could be improved, or if you have a better approach, I genuinely want to hear about it.

Security architecture is complex, and there are often multiple valid ways to solve the same problem. The setup I've described here prioritizes learning and understanding core concepts over production grade completeness. Real production environments would require additional layers like GuardDuty, Security Hub, comprehensive logging, and a more robust network isolation strategy.

If you have feedback, corrections, or suggestions, please reach out that's how we all get better.

Thanks for reading.🙂

Top comments (0)