Skip to content

Instantly share code, notes, and snippets.

@statik
Last active April 23, 2024 03:23
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save statik/f1ac9d6227d98d30c7a7cec0c83f4e64 to your computer and use it in GitHub Desktop.
Save statik/f1ac9d6227d98d30c7a7cec0c83f4e64 to your computer and use it in GitHub Desktop.
WAF with CDK examples
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,
});
}
}
@Patrik-Star
Copy link

Super helpful! Thanks so much!
Any reason why you didn't use cfnRuleGroup?

@awskaran
Copy link

awskaran commented May 5, 2022

This is helpful. Thanks

@fourgates
Copy link

This is amazing @statik! Thank you for putting this together. idk why WAFs are so badly supported in the CDK.

@ikovalyov
Copy link

Thanks

@VladislavKutsobin
Copy link

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 doesnt work :( why it`s happen, please help)

@AK-SCTech
Copy link

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