Last active
October 16, 2024 02:36
-
-
Save statik/f1ac9d6227d98d30c7a7cec0c83f4e64 to your computer and use it in GitHub Desktop.
WAF with CDK examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cdk from "@aws-cdk/core"; | |
import * as wafv2 from "@aws-cdk/aws-wafv2"; | |
// This extends the base cdk stack properties to include a tag name input. | |
export interface StackProps extends cdk.StackProps { | |
tag: string; | |
applicationName?: string; | |
} | |
export class WAFStack extends cdk.Stack { | |
constructor(scope: cdk.Construct, id: string, props: customProps.StackProps) { | |
super(scope, id, props); | |
cdk.Tags.of(this).add('cost-tag', String(props.tag)); | |
const waf = new WAF(this, 'WAFv2'); | |
const devALB = elb.ApplicationLoadBalancer.fromLookup(this, 'devALB', { | |
loadBalancerTags: { | |
// Finds a load balancer matching all tags. | |
'Name': 'foo-dev', | |
}, | |
}); | |
const prodALB = elb.ApplicationLoadBalancer.fromLookup(this, 'prodALB', { | |
loadBalancerTags: { | |
// Finds a load balancer matching all tags. | |
'Name': 'foo-prod', | |
}, | |
}); | |
// Create an association with the dev alb | |
new WebACLAssociation(this, 'DevAssociation',{ | |
resourceArn: devALB.loadBalancerArn, | |
webAclArn: waf.attrArn, | |
}); | |
// Create an association with the prod alb | |
new WebACLAssociation(this, 'ProdAssociation',{ | |
resourceArn: prodALB.loadBalancerArn, | |
webAclArn: waf.attrArn, | |
}); | |
} | |
} | |
interface WafRule { | |
name: string; | |
rule: wafv2.CfnWebACL.RuleProperty; | |
} | |
const awsManagedRules: WafRule[] = [ | |
// AWS IP Reputation list includes known malicious actors/bots and is regularly updated | |
{ | |
name: 'AWS-AWSManagedRulesAmazonIpReputationList', | |
rule: { | |
name: 'AWS-AWSManagedRulesAmazonIpReputationList', | |
priority: 10, | |
statement: { | |
managedRuleGroupStatement: { | |
vendorName: 'AWS', | |
name: 'AWSManagedRulesAmazonIpReputationList', | |
}, | |
}, | |
overrideAction: { | |
none: {}, | |
}, | |
visibilityConfig: { | |
sampledRequestsEnabled: true, | |
cloudWatchMetricsEnabled: true, | |
metricName: 'AWSManagedRulesAmazonIpReputationList', | |
}, | |
}, | |
}, | |
// Common Rule Set aligns with major portions of OWASP Core Rule Set | |
{ | |
name: 'AWS-AWSManagedRulesCommonRuleSet', | |
rule: | |
{ | |
name: 'AWS-AWSManagedRulesCommonRuleSet', | |
priority: 20, | |
statement: { | |
managedRuleGroupStatement: { | |
vendorName: 'AWS', | |
name: 'AWSManagedRulesCommonRuleSet', | |
// Excluding generic RFI body rule for sns notifications | |
// https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html | |
excludedRules: [ | |
{ name: 'GenericRFI_BODY' }, | |
{ name: 'SizeRestrictions_BODY' }, | |
], | |
}, | |
}, | |
overrideAction: { | |
none: {}, | |
}, | |
visibilityConfig: { | |
sampledRequestsEnabled: true, | |
cloudWatchMetricsEnabled: true, | |
metricName: 'AWS-AWSManagedRulesCommonRuleSet', | |
}, | |
}, | |
}, | |
// Blocks common SQL Injection | |
{ | |
name: 'AWSManagedRulesSQLiRuleSet', | |
rule: { | |
name: 'AWSManagedRulesSQLiRuleSet', | |
priority: 30, | |
visibilityConfig: { | |
sampledRequestsEnabled: true, | |
cloudWatchMetricsEnabled: true, | |
metricName: 'AWSManagedRulesSQLiRuleSet', | |
}, | |
overrideAction: { | |
none: {}, | |
}, | |
statement: { | |
managedRuleGroupStatement: { | |
vendorName: 'AWS', | |
name: 'AWSManagedRulesSQLiRuleSet', | |
excludedRules: [], | |
}, | |
}, | |
}, | |
}, | |
// Blocks common PHP attacks such as using high risk variables and methods in the body or queries | |
{ | |
name: 'AWSManagedRulePHP', | |
rule: { | |
name: 'AWSManagedRulePHP', | |
priority: 40, | |
visibilityConfig: { | |
sampledRequestsEnabled: true, | |
cloudWatchMetricsEnabled: true, | |
metricName: 'AWSManagedRulePHP', | |
}, | |
overrideAction: { | |
none: {}, | |
}, | |
statement: { | |
managedRuleGroupStatement: { | |
vendorName: 'AWS', | |
name: 'AWSManagedRulesPHPRuleSet', | |
excludedRules: [], | |
}, | |
}, | |
}, | |
}, | |
// Blocks attacks targeting LFI(Local File Injection) for linux systems | |
{ | |
name: 'AWSManagedRuleLinux', | |
rule: { | |
name: 'AWSManagedRuleLinux', | |
priority: 50, | |
visibilityConfig: { | |
sampledRequestsEnabled: true, | |
cloudWatchMetricsEnabled: true, | |
metricName: 'AWSManagedRuleLinux', | |
}, | |
overrideAction: { | |
none: {}, | |
}, | |
statement: { | |
managedRuleGroupStatement: { | |
vendorName: 'AWS', | |
name: 'AWSManagedRulesLinuxRuleSet', | |
excludedRules: [], | |
}, | |
}, | |
}, | |
}, | |
]; | |
export class WAF extends wafv2.CfnWebACL { | |
constructor(scope: cdk.Construct, id: string) { | |
super(scope, id,{ | |
defaultAction: { allow: {} }, | |
visibilityConfig: { | |
cloudWatchMetricsEnabled: true, | |
metricName: 'foo-waf', | |
sampledRequestsEnabled: false, | |
}, | |
scope: 'REGIONAL', | |
name: 'foo-prod-waf', | |
rules: awsManagedRules.map(wafRule => wafRule.rule), | |
}); | |
} | |
} | |
export class WebACLAssociation extends wafv2.CfnWebACLAssociation { | |
constructor(scope: cdk.Construct, id: string, props: wafv2.CfnWebACLAssociationProps) { | |
super(scope, id,{ | |
resourceArn: props.resourceArn, | |
webAclArn: props.webAclArn, | |
}); | |
} | |
} |
This is helpful. Thanks
This is amazing @statik! Thank you for putting this together. idk why WAFs are so badly supported in the CDK.
Thanks
Hi, i just done the same, also added ip white list separate and beside the AWSManagedRulesCommonRuleSet . And now, ipset rule working properly, but AWSManagedRulesCommonRuleSet doesnt work... I use same code from you. I try to check these rules but it doesn
t work :( why it`s happen, please help)
Great, thanks for putting this together. Have used most of them but just currently need the rules for Known Bad Inputs and Anonymous IP list configuration.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Super helpful! Thanks so much!
Any reason why you didn't use cfnRuleGroup?