From d69b000ee2d92fc3429f3ca4b92f6108b82d548a Mon Sep 17 00:00:00 2001 From: Khai Do Date: Thu, 2 Jan 2025 11:26:04 -0800 Subject: [PATCH 1/3] [IT-3995] Setup WAF for application Web application firewall for agora app, enabled with the AWS managed Baseline core rule set[1] to protect again OWASP top 10 vunerablities[2]. Additional rules[3] can be added by updating the WebAcl rules object. [1] https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-baseline.html#aws-managed-rule-groups-baseline-crs [2] https://owasp.org/www-project-top-ten/ [3] https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-baseline.html --- requirements-dev.txt | 4 ++-- requirements.txt | 6 ++--- src/load_balancer_stack.py | 47 +++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 1f2bf77..60c614b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,2 @@ -pre-commit~=3.8.0 -pytest==6.2.5 +pre-commit~=3.8 +pytest~=6.2 diff --git a/requirements.txt b/requirements.txt index 92c10ed..0246ca6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -aws-cdk-lib==2.139.0 -constructs>=10.0.0,<11.0.0 -boto3>=1.34.1 +aws-cdk-lib~=2.139 +constructs~=10.0 +boto3~=1.34 diff --git a/src/load_balancer_stack.py b/src/load_balancer_stack.py index 32dd73f..32c9159 100644 --- a/src/load_balancer_stack.py +++ b/src/load_balancer_stack.py @@ -3,6 +3,7 @@ from aws_cdk import ( aws_ec2 as ec2, aws_elasticloadbalancingv2 as elbv2, + aws_wafv2 as wafv2 ) from constructs import Construct @@ -10,7 +11,7 @@ class LoadBalancerStack(cdk.Stack): """ - API Gateway to allow access to ECS app from the internet + Load Balancer to allow access to ECS app from the internet """ def __init__( @@ -21,6 +22,50 @@ def __init__( self.alb = elbv2.ApplicationLoadBalancer( self, "AppLoadBalancer", vpc=vpc, internet_facing=True ) + + # WAF to protect against common web attacks (OWASP Top 10) + web_acl = wafv2.CfnWebACL(self,"WebAcl", + name="AppWebAcl", + default_action=wafv2.CfnWebACL.DefaultActionProperty( + allow=wafv2.CfnWebACL.AllowActionProperty() + ), + scope="REGIONAL", + visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( + cloud_watch_metrics_enabled=True, + metric_name="AWSManagedRulesCommonRuleSet", + sampled_requests_enabled=True + ), + rules=[wafv2.CfnWebACL.RuleProperty( + name="AWSManagedRulesCommonRuleSet", + priority=0, + statement=wafv2.CfnWebACL.StatementProperty( + managed_rule_group_statement=wafv2.CfnWebACL.ManagedRuleGroupStatementProperty( + name="AWSManagedRulesCommonRuleSet", + vendor_name="AWS", + excluded_rules=[] + ) + ), + action=wafv2.CfnWebACL.RuleActionProperty( + block={} + ), + visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( + cloud_watch_metrics_enabled=True, + metric_name="AWSManagedRulesCommonRuleSet", + sampled_requests_enabled=True + ), + override_action=wafv2.CfnWebACL.OverrideActionProperty( + none={} + ) + )] + + ) + + wafv2.CfnWebACLAssociation( + self, "web_acl_association", + resource_arn=self.alb.load_balancer_arn, + web_acl_arn=web_acl.attr_arn + ) + cdk.CfnOutput( self, "LoadBalancerDns", From 6a6257f89e3d7651b6fea123fa255f40aab70871 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 19:34:38 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/load_balancer_stack.py | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/load_balancer_stack.py b/src/load_balancer_stack.py index 32c9159..b5af334 100644 --- a/src/load_balancer_stack.py +++ b/src/load_balancer_stack.py @@ -3,7 +3,7 @@ from aws_cdk import ( aws_ec2 as ec2, aws_elasticloadbalancingv2 as elbv2, - aws_wafv2 as wafv2 + aws_wafv2 as wafv2, ) from constructs import Construct @@ -24,7 +24,9 @@ def __init__( ) # WAF to protect against common web attacks (OWASP Top 10) - web_acl = wafv2.CfnWebACL(self,"WebAcl", + web_acl = wafv2.CfnWebACL( + self, + "WebAcl", name="AppWebAcl", default_action=wafv2.CfnWebACL.DefaultActionProperty( allow=wafv2.CfnWebACL.AllowActionProperty() @@ -33,37 +35,35 @@ def __init__( visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( cloud_watch_metrics_enabled=True, metric_name="AWSManagedRulesCommonRuleSet", - sampled_requests_enabled=True + sampled_requests_enabled=True, ), - rules=[wafv2.CfnWebACL.RuleProperty( - name="AWSManagedRulesCommonRuleSet", - priority=0, - statement=wafv2.CfnWebACL.StatementProperty( - managed_rule_group_statement=wafv2.CfnWebACL.ManagedRuleGroupStatementProperty( - name="AWSManagedRulesCommonRuleSet", - vendor_name="AWS", - excluded_rules=[] - ) - ), - action=wafv2.CfnWebACL.RuleActionProperty( - block={} - ), - visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( - cloud_watch_metrics_enabled=True, - metric_name="AWSManagedRulesCommonRuleSet", - sampled_requests_enabled=True - ), - override_action=wafv2.CfnWebACL.OverrideActionProperty( - none={} + rules=[ + wafv2.CfnWebACL.RuleProperty( + name="AWSManagedRulesCommonRuleSet", + priority=0, + statement=wafv2.CfnWebACL.StatementProperty( + managed_rule_group_statement=wafv2.CfnWebACL.ManagedRuleGroupStatementProperty( + name="AWSManagedRulesCommonRuleSet", + vendor_name="AWS", + excluded_rules=[], + ) + ), + action=wafv2.CfnWebACL.RuleActionProperty(block={}), + visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( + cloud_watch_metrics_enabled=True, + metric_name="AWSManagedRulesCommonRuleSet", + sampled_requests_enabled=True, + ), + override_action=wafv2.CfnWebACL.OverrideActionProperty(none={}), ) - )] - + ], ) wafv2.CfnWebACLAssociation( - self, "web_acl_association", + self, + "web_acl_association", resource_arn=self.alb.load_balancer_arn, - web_acl_arn=web_acl.attr_arn + web_acl_arn=web_acl.attr_arn, ) cdk.CfnOutput( From 7bc5ab00b45b587ece44d52fdd874b903902f714 Mon Sep 17 00:00:00 2001 From: Khai Do Date: Fri, 3 Jan 2025 15:11:16 -0800 Subject: [PATCH 3/3] add AWSManagedRulesKnownBadInputsRuleSet --- src/load_balancer_stack.py | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/load_balancer_stack.py b/src/load_balancer_stack.py index b5af334..166f446 100644 --- a/src/load_balancer_stack.py +++ b/src/load_balancer_stack.py @@ -23,21 +23,20 @@ def __init__( self, "AppLoadBalancer", vpc=vpc, internet_facing=True ) - # WAF to protect against common web attacks (OWASP Top 10) + # WAF to protect against common web attacks web_acl = wafv2.CfnWebACL( self, "WebAcl", - name="AppWebAcl", - default_action=wafv2.CfnWebACL.DefaultActionProperty( - allow=wafv2.CfnWebACL.AllowActionProperty() - ), scope="REGIONAL", + default_action=wafv2.CfnWebACL.DefaultActionProperty(allow={}), visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( cloud_watch_metrics_enabled=True, - metric_name="AWSManagedRulesCommonRuleSet", + metric_name="WebAclMetrics", sampled_requests_enabled=True, ), rules=[ + # Rules that provide protection against exploitation of a wide range of vulnerabilities, + # including those described in OWASP top 10 publications wafv2.CfnWebACL.RuleProperty( name="AWSManagedRulesCommonRuleSet", priority=0, @@ -45,23 +44,39 @@ def __init__( managed_rule_group_statement=wafv2.CfnWebACL.ManagedRuleGroupStatementProperty( name="AWSManagedRulesCommonRuleSet", vendor_name="AWS", - excluded_rules=[], ) ), - action=wafv2.CfnWebACL.RuleActionProperty(block={}), + override_action=wafv2.CfnWebACL.OverrideActionProperty(none={}), visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( cloud_watch_metrics_enabled=True, metric_name="AWSManagedRulesCommonRuleSet", sampled_requests_enabled=True, ), + ), + # Rules to block request patterns that are known to be invalid and are associated with + # exploitation or discovery of vulnerabilities. + wafv2.CfnWebACL.RuleProperty( + name="AWSManagedRulesKnownBadInputsRuleSet", + priority=1, + statement=wafv2.CfnWebACL.StatementProperty( + managed_rule_group_statement=wafv2.CfnWebACL.ManagedRuleGroupStatementProperty( + vendor_name="AWS", + name="AWSManagedRulesKnownBadInputsRuleSet", + ) + ), override_action=wafv2.CfnWebACL.OverrideActionProperty(none={}), - ) + visibility_config=wafv2.CfnWebACL.VisibilityConfigProperty( + sampled_requests_enabled=True, + cloud_watch_metrics_enabled=True, + metric_name="AWSManagedRulesKnownBadInputsRuleSet", + ), + ), ], ) wafv2.CfnWebACLAssociation( self, - "web_acl_association", + "WeAclAssociation", resource_arn=self.alb.load_balancer_arn, web_acl_arn=web_acl.attr_arn, )