Migrating from AWS WAF Classic to WAF v2: A Comprehensive Guide
A detailed roadmap for migrating to AWS WAF v2, covering planning, execution, testing, and rollback strategies with practical code examples to enhance your web security posture.
Introduction
AWS Web Application Firewall (WAF) helps protect your web applications from common web exploits that could affect application availability, compromise security, or consume excessive resources. In 2019, AWS introduced WAF v2 with significant improvements over WAF Classic, including simplified rule management, new rule capabilities, and better performance.
This article provides a detailed roadmap for migrating from WAF Classic to WAF v2, covering planning, execution, testing, and rollback strategies. Whether you're managing a single web application or a complex enterprise environment, this guide will help you navigate the migration process with confidence.
Why Migrate to WAF v2?
Before diving into the migration process, let's understand why migrating to WAF v2 is beneficial:
- Enhanced rule capabilities: WAF v2 offers more sophisticated rule options, including JSON body inspection and custom request/response handling
- Simplified management: Improved console experience and API structure
- Better performance: More efficient rule evaluation and processing
- Advanced features: CAPTCHA, Challenge actions, and label matching
- Future-proofing: AWS is focusing development efforts on WAF v2, with WAF Classic receiving minimal updates
Migration Planning Phase
Step 1: Inventory Your Current WAF Classic Resources
Begin by documenting all your WAF Classic resources:
# List all WAF Classic Web ACLs (Global)aws waf list-web-acls
# List all WAF Classic Regional Web ACLsaws waf-regional list-web-acls --region <your-region>
# For each Web ACL, get detailed configurationaws waf-regional get-web-acl --web-acl-id <web-acl-id> --region <your-region>
# List resources associated with each Web ACLaws waf-regional list-resources-for-web-acl --web-acl-id <web-acl-id> --region <your-region>
# List rule groupsaws waf-regional list-rule-groups --region <your-region>
# List IP setsaws waf-regional list-ip-sets --region <your-region>
# List regex pattern setsaws waf-regional list-regex-pattern-sets --region <your-region>Create a detailed inventory spreadsheet that includes:
- Web ACL names and IDs
- Default actions (ALLOW or BLOCK)
- Associated resources (ALBs, API Gateways, etc.)
- Rules and rule groups with their actions and conditions
- IP sets and regex pattern sets
Step 2: Understand WAF v2 Concepts and Differences
Before migrating, familiarize yourself with key WAF v2 concepts:
- Scope: WAF v2 requires explicit scope definition (REGIONAL or CLOUDFRONT)
- Web ACL Capacity Units (WCUs): WAF v2 uses WCUs to measure rule complexity
- Rule Structure: WAF v2 uses a nested structure for rules and statements
- Visibility Configuration: Required for all entities in WAF v2
- Rule Action: WAF v2 supports additional actions like CAPTCHA and Challenge
Step 3: Map WAF Classic Components to WAF v2
Use this mapping table to understand how WAF Classic components translate to WAF v2:
WAF Classic Component | WAF v2 Equivalent |
|---|---|
Web ACL | Web ACL (with scope) |
Rule | Rule |
Rule Group | Rule Group |
IP Match Condition | IP Set Reference Statement |
Geo Match Condition | Geo Match Condition |
String Match Condition | Byte Match Statement or Regex Pattern Set Reference Statement |
Regex Match Condition | Regex Pattern Set Reference Statement |
Size Constraint Condition | Size Constraint Condition |
SQL Injection Match Condition | SQL Injection Match Condition |
XSS Match Condition | XSS Match Condition |
Rate-based Rule | Rate-based Rule Statement |
Step 4: Create a Migration Strategy
Develop a migration strategy that includes:
- Timeline: Set realistic deadlines for each migration phase
- Resource prioritization: Identify which Web ACLs to migrate first
- Testing approach: Define how you'll validate WAF v2 configurations
- Rollback plan: Document steps to revert to WAF Classic if needed
- Monitoring strategy: Determine how you'll compare WAF Classic vs WAF v2 performance
Execution Phase
Step 1: Create IP Sets and Regex Pattern Sets in WAF v2
Start by migrating your IP sets and regex pattern sets:
# Create an IP set in WAF v2aws wafv2 create-ip-set \ --name "MigratedIPSet-1" \ --scope "REGIONAL" \ --ip-address-version "IPV4" \ --addresses "192.0.2.0/24" "198.51.100.0/24" \ --region <your-region>
# Create a regex pattern set in WAF v2aws wafv2 create-regex-pattern-set \ --name "MigratedRegexSet-1" \ --scope "REGIONAL" \ --regular-expression-list '[{"RegexString":"badbot.*"}, {"RegexString":"malicious.*"}]' \ --region <your-region>Step 2: Create Rule Groups in WAF v2
Next, create rule groups that match your WAF Classic rule groups:
aws wafv2 create-rule-group \ --name "MigratedRuleGroup-1" \ --scope "REGIONAL" \ --capacity 100 \ --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=MigratedRuleGroup1 \ --rules file://rules.json \ --region <your-region>
Where rules.json contains your rule definitions. Here's an example structure:
[ { "Name": "SQLiRule", "Priority": 1, "Statement": { "SqliMatchStatement": { "FieldToMatch": { "AllQueryArguments": {} }, "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ] } }, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "SQLiRule" } }]
Step 3: Create Web ACLs in WAF v2
Now create your Web ACLs in WAF v2:
aws wafv2 create-web-acl \ --name "MigratedWebACL-1" \ --scope "REGIONAL" \ --default-action Allow={} \ --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=MigratedWebACL1 \ --rules file://web-acl-rules.json \ --region <your-region>
Where web-acl-rules.json contains your Web ACL rules, including any rule group references:
[ { "Name": "RuleGroupReference1", "Priority": 0, "Statement": { "RuleGroupReferenceStatement": { "ARN": "arn:aws:wafv2:<region>:<account-id>:regional/rulegroup/MigratedRuleGroup-1/<id>" } }, "OverrideAction": { "None": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "RuleGroupReference1" } }, { "Name": "RateLimitRule", "Priority": 1, "Statement": { "RateBasedStatement": { "Limit": 1000, "AggregateKeyType": "IP" } }, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "RateLimitRule" } }]
Step 4: Initial Testing with Count Mode
Before fully implementing your WAF v2 rules, set them to Count mode for testing:
# Update a rule to use Count modeaws wafv2 update-web-acl \ --name "MigratedWebACL-1" \ --scope "REGIONAL" \ --id <web-acl-id> \ --default-action Allow={} \ --rules file://count-mode-rules.json \ --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=MigratedWebACL1 \ --lock-token <lock-token> \ --region <your-region>
In count-mode-rules.json, set the action to Count instead of Block:
[ { "Name": "SQLiRule", "Priority": 1, "Statement": { "SqliMatchStatement": { "FieldToMatch": { "AllQueryArguments": {} }, "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ] } }, "Action": { "Count": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "SQLiRule" } }]Testing Phase
Step 1: Set Up Logging for Both WAF Versions
Enable logging for both WAF Classic and WAF v2 to compare their behavior:
# Enable logging for WAF Classicaws waf-regional put-logging-configuration \ --log-destination-configs 'arn:aws:s3:::<bucket-name>/waf-classic-logs/' \ --resource-arn <web-acl-arn> \ --region <your-region>
# Enable logging for WAF v2aws wafv2 put-logging-configuration \ --resource-arn <web-acl-arn> \ --log-destination-configs 'arn:aws:firehose:us-east-1:<account-id>:deliverystream/aws-waf-logs-delivery-stream' \ --redacted-fields '{"SingleHeader": {"Name": "password"}}' \ --region <your-region>Step 2: Analyze Traffic Patterns
Compare logs between WAF Classic and WAF v2 to ensure:
- Similar request blocking patterns
- No unexpected blocks or allows
- Comparable rate limiting behavior
Use CloudWatch metrics to compare:
- Allowed requests
- Blocked requests
- Counted requests (for rules in Count mode)
Step 3: Gradual Rule Transition
Once you're confident in your WAF v2 configuration, gradually transition rules from Count to Block mode:
- Start with lower-risk rules (e.g., rate limiting)
- Monitor for any unexpected blocks
- Gradually enable higher-risk rules (e.g., SQL injection protection)
Step 4: Associate Resources with WAF v2
When you're ready to fully migrate, associate your resources with the WAF v2 Web ACLs:
# Associate an ALB with a WAF v2 Web ACLaws wafv2 associate-web-acl \ --web-acl-arn <web-acl-arn> \ --resource-arn <alb-arn> \ --region <your-region>
# Associate an API Gateway stage with a WAF v2 Web ACLaws wafv2 associate-web-acl \ --web-acl-arn <web-acl-arn> \ --resource-arn <api-gateway-stage-arn> \ --region <your-region>
# Associate a CloudFront distribution with a WAF v2 Web ACL (global scope)aws cloudfront update-distribution \ --id <distribution-id> \ --web-acl-id <web-acl-id> \ --region us-east-1
Rollback Plan
Despite careful planning, you might need to roll back to WAF Classic. Here's how to prepare:
Step 1: Maintain WAF Classic Configuration
Keep your WAF Classic configuration intact until you're fully confident in your WAF v2 setup:
# Do not delete WAF Classic resources until migration is complete and verifiedStep 2: Document Association Commands
Document the commands to re-associate resources with WAF Classic:
# Re-associate an ALB with a WAF Classic Web ACLaws waf-regional associate-web-acl \ --web-acl-id <web-acl-id> \ --resource-arn <alb-arn> \ --region <your-region>
# Re-associate an API Gateway stage with a WAF Classic Web ACLaws waf-regional associate-web-acl \ --web-acl-id <web-acl-id> \ --resource-arn <api-gateway-stage-arn> \ --region <your-region>Step 3: Create a Rollback Script
Prepare a script that can quickly:
- Disassociate resources from WAF v2
- Re-associate resources with WAF Classic
- Verify the associations
Post-Migration Optimization
After successfully migrating to WAF v2, consider these optimization steps:
Step 1: Leverage WAF v2-Specific Features
Enhance your security posture with WAF v2-specific features:
- JSON Body Inspection: Add rules to inspect JSON payloads
- CAPTCHA and Challenge Actions: Implement bot mitigation
- Custom Request and Response Handling: Configure custom error pages
- Label Matching: Use labels to create more sophisticated rule chains
Step 2: Optimize WCU Usage
Review your Web ACL Capacity Units (WCUs) usage:
- Identify rules consuming the most WCUs
- Consider consolidating similar rules
- Use scope-down statements to limit expensive inspections
Step 3: Implement Comprehensive Logging and Monitoring
Set up advanced monitoring:
- Configure detailed logging to Amazon S3 or Kinesis Data Firehose
- Create CloudWatch dashboards for WAF metrics
- Set up alerts for unusual blocking patterns
Real-World Migration Example
To illustrate the migration process, let's walk through a real-world example:
Scenario
A company has a WAF Classic Web ACL protecting several ALBs with the following configuration:
- Default action: Allow
- SQL Injection protection rule
- Cross-site scripting (XSS) protection rule
- Rate-based rule limiting to 2000 requests per 5 minutes
- IP blacklist rule
Migration Steps
1. Create IP Set in WAF v2:
bash aws wafv2 create-ip-set \ --name "BlockedIPs" \ --scope "REGIONAL" \ --ip-address-version "IPV4" \ --addresses "192.0.2.0/24" "198.51.100.0/24" \ --region us-east-1
2. Create Web ACL in WAF v2:
aws wafv2 create-web-acl \ --name "MainProtection" \ --scope "REGIONAL" \ --default-action Allow={} \ --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=MainProtection \ --rules file://rules.json \ --region us-east-1
3. Test with Count Mode:
The company ran both WAF versions in parallel for two weeks, with WAF v2 in Count mode.
4. Analyze Results:
After comparing logs, they found WAF v2 was more effective at catching SQL injection attempts.
5. Gradual Transition:
They gradually switched rules from Count to Block mode over a one-week period.
6. Complete Migration:
After confirming no false positives, they fully migrated all resources to WAF v2.
Conclusion
Migrating from WAF Classic to WAF v2 requires careful planning and execution, but the benefits are substantial. WAF v2 offers enhanced protection capabilities, better performance, and a more intuitive management experience.
By following this comprehensive guide, you can ensure a smooth migration process while minimizing the risk of security gaps or application disruptions. Remember that a successful migration isn't just about moving configurations—it's about leveraging the new capabilities of WAF v2 to enhance your overall security posture.
Have you migrated from WAF Classic to WAF v2? Share your experiences and insights in the comments below!
Additional Resources
- [AWS WAF Developer Guide]( https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html )
- [AWS WAF Migration Guide]( https://docs.aws.amazon.com/waf/latest/developerguide/waf-migrating-from-classic.html )
- [AWS WAF Pricing]( https://aws.amazon.com/waf/pricing/ )
- [AWS WAF Security Automations]( https://aws.amazon.com/solutions/implementations/aws-waf-security-automations/ )
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article