From d6b45662c65d552767d2ec79f91fa8cc69efc0a6 Mon Sep 17 00:00:00 2001 From: daknhh Date: Sat, 22 Jan 2022 17:12:35 +0100 Subject: [PATCH 1/2] Fix General Policy --- lib/plattform-wafv2-cdk-automation-stack.ts | 52 ++++++++++----------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/plattform-wafv2-cdk-automation-stack.ts b/lib/plattform-wafv2-cdk-automation-stack.ts index 54c6decb..03717f45 100644 --- a/lib/plattform-wafv2-cdk-automation-stack.ts +++ b/lib/plattform-wafv2-cdk-automation-stack.ts @@ -163,35 +163,33 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { { console.log("Creating DEFAULT Policy.") const novalue = null + let mangedrule; + let ExcludeRules; + let OverrideAction; + const preProcessRuleGroups = [] + for(mangedrule of props.config.WebAcl.ManagedRuleGroups){ + if(mangedrule.ExcludeRules){ + ExcludeRules = toCamel(mangedrule.ExcludeRules) + OverrideAction = mangedrule.OverrideAction + } + else{ + ExcludeRules = [] + OverrideAction = { "type": "NONE" } + } + if(mangedrule.Version == ""){ + preProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor, + "managedRuleGroupName":mangedrule.Name,"version": novalue},"overrideAction": OverrideAction, + "ruleGroupArn": novalue,"excludeRules": ExcludeRules,"ruleGroupType": "ManagedRuleGroup"});} + else{ + preProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor, + "managedRuleGroupName":mangedrule.Name,"version": mangedrule.Version},"overrideAction": OverrideAction, + "ruleGroupArn": novalue,"excludeRules": ExcludeRules,"ruleGroupType": "ManagedRuleGroup"});} + } const securityservicepolicydata = { "type":"WAFV2", "defaultAction":{ "type":"ALLOW" }, - "preProcessRuleGroups": [ - { - "managedRuleGroupIdentifier": { - "vendorName": "AWS", - "managedRuleGroupName": "AWSManagedRulesCommonRuleSet", - "version": novalue - }, - "overrideAction": { "type": "NONE" }, - "ruleGroupArn": novalue, - "excludeRules": [], - "ruleGroupType": "ManagedRuleGroup" - } - ], - "postProcessRuleGroups": [ - { - "managedRuleGroupIdentifier": { - "vendorName": "AWS", - "managedRuleGroupName": "AWSManagedRulesAmazonIpReputationList", - "version": novalue - }, - "overrideAction": { "type": "NONE" }, - "ruleGroupArn": novalue, - "excludeRules": [], - "ruleGroupType": "ManagedRuleGroup" - } - ], + "preProcessRuleGroups": preProcessRuleGroups, + "postProcessRuleGroups": [], "overrideCustomerWebACLAssociation":true, "loggingConfiguration": { "logDestinationConfigs":["${S3DeliveryStream.Arn}"] @@ -419,7 +417,7 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { sampledRequestsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.SampledRequestsEnabled, cloudWatchMetricsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled, metricName: rulename + "-metric", - }, + } } CfnRuleProperties.push(CfnRuleProperty) rulegroupcounter++ From 82c5ed993fef84517e510db84237cc09b871ae50 Mon Sep 17 00:00:00 2001 From: daknhh Date: Sun, 23 Jan 2022 16:00:02 +0100 Subject: [PATCH 2/2] Captcha Action support --- CHANGELOG.md | 13 +++++ README.md | 2 +- bin/plattform-wafv2-cdk-automation.ts | 53 ++++++++++++------ lib/plattform-wafv2-cdk-automation-stack.ts | 59 ++++++++++++++++----- package.json | 6 +-- values/calculatecapacity.json | 7 +-- 6 files changed, 106 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32b93165..86b86cc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ ## Released +## 1.0.3 + +### Added + +New Support for Captcha - You can now add Captcha as Action to your WAFs. AWS WAF Captcha is available in the US East (N. Virginia), US West (Oregon), Europe (Frankfurt), South America (Sao Paulo), and Asia Pacific (Singapore) AWS Regions and supports Application Load Balancer, Amazon API Gateway, and AWS AppSync resources. +## 1.0.2 + +### Added +#### Rule Name +You can now name your Rules. If you define a Name in your RulesArray the Name + a Base36 Timestamp will be used for creation of your Rule - otherwise a name will be generated. This will help you to query your logs in Athena. The same Rulename also apply to the metric just with adding "-metric" to the name. +## 1.0.1 + +Updated Readme - Community Release ## 1.0.0 ### Added diff --git a/README.md b/README.md index 2575883c..26dc8bc3 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ AWS Web Application Firewalls (WAFs) protect web applications and APIs from typi 8. Stopping deployment if soft limit will be exceeded: **Firewall Manager policies per organization per Region (L-0B28E140)** - **Maximum number of web ACL capacity units in a web ACL in WAF for regional (L-D9F31E8A)** 9. NEW **RegexMatchStatement** and **IPSetReferenceStatement** is working now šŸš€ 10. NEW You can now name your Rules. If you define a Name in your RulesArray the Name + a Base36 Timestamp will be used for creation of your Rule - otherwise a name will be generated. This will help you to query your logs in Athena. The same Rulename also apply to the metric just with adding "-metric" to the name. - +11. New Support for Captcha - You can now add Captcha as Action to your WAFs. This help you to block unwanted bot traffic by requiring users to successfully complete challenges before their web request are allowed to reach AWS WAF protected resources. AWS WAF Captcha is available in the US East (N. Virginia), US West (Oregon), Europe (Frankfurt), South America (Sao Paulo), and Asia Pacific (Singapore) AWS Regions and supports Application Load Balancer, Amazon API Gateway, and AWS AppSync resources. ## Coming soon: 1. Deployment via Teamcity diff --git a/bin/plattform-wafv2-cdk-automation.ts b/bin/plattform-wafv2-cdk-automation.ts index 8cc473d8..49dffc8a 100644 --- a/bin/plattform-wafv2-cdk-automation.ts +++ b/bin/plattform-wafv2-cdk-automation.ts @@ -2,7 +2,7 @@ import { PlattformWafv2CdkAutomationStack, Config } from "../lib/plattform-wafv2-cdk-automation-stack"; import * as cdk from "aws-cdk-lib"; import * as fs from "fs"; -import { WAFV2Client, CheckCapacityCommand, CheckCapacityCommandInput, Statement,CreateRegexPatternSetCommandInput, CreateRegexPatternSetCommand, DescribeManagedRuleGroupCommand, DescribeManagedRuleGroupCommandInput, CreateRegexPatternSetRequest, RegexPatternSet } from "@aws-sdk/client-wafv2"; +import { WAFV2Client, CheckCapacityCommandOutput, CheckCapacityCommand, CheckCapacityCommandInput, DescribeManagedRuleGroupCommand, DescribeManagedRuleGroupCommandInput } from "@aws-sdk/client-wafv2"; import * as quota from "@aws-sdk/client-service-quotas"; import * as cloudformation from "@aws-sdk/client-cloudformation" import { FMSClient, ListPoliciesCommand, ListPoliciesCommandInput } from "@aws-sdk/client-fms"; @@ -64,8 +64,8 @@ async function CheckCapacity(Scope: string, calculated_capacity_json: object): P Rules: newRules }; const command = new CheckCapacityCommand(input); - const response = await client.send(command); - return response.Capacity || 0 + const response: any = await client.send(command); + return response.Capacity | 0 } async function CheckQuota(Quoata: string): Promise{ let current_quota = 0 @@ -121,8 +121,8 @@ async function GetManagedRuleCapacity(Vendor: string, Name: string, Scope: strin Scope: Scope } const command = new DescribeManagedRuleGroupCommand(input); - const response = await client.send(command) - return response.Capacity || 0 + const response: any = await client.send(command); + return response.Capacity | 0 } else{ const input: DescribeManagedRuleGroupCommandInput = { @@ -132,8 +132,8 @@ async function GetManagedRuleCapacity(Vendor: string, Name: string, Scope: strin VersionName: Version } const command = new DescribeManagedRuleGroupCommand(input); - const response = await client.send(command) - return response.Capacity || 0 + const response: any = await client.send(command); + return response.Capacity | 0 } } @@ -178,6 +178,17 @@ if (configFile && fs.existsSync(configFile)) { else{ deploymentregion = process.env.REGION || "eu-central-1" } + console.log(` + ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•— + ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā•šā•ā•ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā•šā–ˆā–ˆā•— ā–ˆā–ˆā•”ā• + ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā•— ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā•— ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā•šā–ˆā–ˆā–ˆā–ˆā•”ā• + ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ā•šā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā•šā–ˆā–ˆā•”ā• + ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā–ˆā•”ā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā•šā–ˆā–ˆā–ˆā•”ā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ + ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā•šā•ā•ā• ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā•ā•šā•ā• ā•šā•ā•ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•šā•ā•ā• ā•šā•ā• ā•šā•ā•ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā• ā•šā•ā• + `); + console.log("\x1b[36m","\n by globaldatanet","\x1b[0m"); + console.log("\nšŸ‘¤ AWS Profile used: ","\x1b[33m","\n " + process.env.AWSUME_PROFILE,"\x1b[0m"); + console.log("šŸŒŽ CDK deployment region:","\x1b[33m","\n "+deploymentregion,"\x1b[0m \n") if(config.General.DeployHash == ""){ Temp_Hash = Date.now().toString(36) config.General.DeployHash = Temp_Hash @@ -213,14 +224,26 @@ if (configFile && fs.existsSync(configFile)) { } else{ while (count < config.WebAcl.Rules.length) { - const rule_calculated_capacity_json = []; - const temp_template = template; - temp_template.Statement = config.WebAcl.Rules[count].Statement; - temp_template.Action = config.WebAcl.Rules[count].Action; - rule_calculated_capacity_json.push(temp_template); - const capacity = await CheckCapacity(config.WebAcl.Scope, rule_calculated_capacity_json); - - config.RuleCapacities.push(capacity); + if("Captcha" in config.WebAcl.Rules[count].Action){ + const rule_calculated_capacity_json = []; + const temp_template = template; + temp_template.Statement = config.WebAcl.Rules[count].Statement; + temp_template.Action = config.WebAcl.Rules[count].Action; + temp_template.CaptchaConfig = config.WebAcl.Rules[count].CaptchaConfig; + rule_calculated_capacity_json.push(temp_template); + const capacity = await CheckCapacity(config.WebAcl.Scope, rule_calculated_capacity_json); + config.RuleCapacities.push(capacity); + } + else{ + const rule_calculated_capacity_json = []; + const temp_template = template; + temp_template.Statement = config.WebAcl.Rules[count].Statement; + temp_template.Action = config.WebAcl.Rules[count].Action; + delete temp_template.CaptchaConfig + rule_calculated_capacity_json.push(temp_template); + const capacity = await CheckCapacity(config.WebAcl.Scope, rule_calculated_capacity_json); + config.RuleCapacities.push(capacity); + } count++ } calculate_capacity_sum = config.RuleCapacities.reduce(function (a, b) { diff --git a/lib/plattform-wafv2-cdk-automation-stack.ts b/lib/plattform-wafv2-cdk-automation-stack.ts index 03717f45..73d75d64 100644 --- a/lib/plattform-wafv2-cdk-automation-stack.ts +++ b/lib/plattform-wafv2-cdk-automation-stack.ts @@ -34,7 +34,8 @@ interface RulesArray{ Name?: string, Statement: any, Action: any, - VisibilityConfig: any + VisibilityConfig: any, + CaptchaConfig?: any, } function toCamel(o: any) { @@ -220,7 +221,23 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { else{ rulename = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash } - const CfnRuleProperty: wafv2.CfnRuleGroup.RuleProperty = { + let CfnRuleProperty: wafv2.CfnRuleGroup.RuleProperty + if("Captcha" in statement.Action){ + CfnRuleProperty = { + name: rulename, + priority: count, + action: toCamel(statement.Action), + statement: toCamel(statement.Statement), + visibilityConfig: { + sampledRequestsEnabled: statement.VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled, + metricName: rulename + "-metric", + }, + captchaConfig: toCamel(statement.CaptchaConfig), + } + } + else{ + CfnRuleProperty = { name: rulename, priority: count, action: toCamel(statement.Action), @@ -230,7 +247,7 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled, metricName: rulename + "-metric", }, - }; + };} rules.push(CfnRuleProperty) count +=1 } @@ -408,17 +425,35 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { else{ rulename = rulegroupcounter.toString() } - const CfnRuleProperty: wafv2.CfnRuleGroup.RuleProperty = { - name: rulename, - priority: rulegroupcounter, - action: toCamel(props.config.WebAcl.Rules[statementindex].Action), - statement: toCamel(props.config.WebAcl.Rules[statementindex].Statement), - visibilityConfig: { - sampledRequestsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled, - metricName: rulename + "-metric", + let CfnRuleProperty: wafv2.CfnRuleGroup.RuleProperty + if("Captcha" in props.config.WebAcl.Rules[statementindex].Action){ + CfnRuleProperty = { + name: rulename, + priority: rulegroupcounter, + action: toCamel(props.config.WebAcl.Rules[statementindex].Action), + statement: toCamel(props.config.WebAcl.Rules[statementindex].Statement), + visibilityConfig: { + sampledRequestsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled, + metricName: rulename + "-metric", + }, + captchaConfig: toCamel(props.config.WebAcl.Rules[statementindex].CaptchaConfig), + } + } + else{ + CfnRuleProperty = { + name: rulename, + priority: rulegroupcounter, + action: toCamel(props.config.WebAcl.Rules[statementindex].Action), + statement: toCamel(props.config.WebAcl.Rules[statementindex].Statement), + visibilityConfig: { + sampledRequestsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled, + metricName: rulename + "-metric", + } } } + CfnRuleProperties.push(CfnRuleProperty) rulegroupcounter++ } diff --git a/package.json b/package.json index 6c20c043..4ee879b6 100644 --- a/package.json +++ b/package.json @@ -27,14 +27,14 @@ "typescript": "~3.9.7" }, "dependencies": { - "aws-cdk-lib": "^2.2.0", - "constructs": "^10.0.0", "@aws-sdk/client-cloudformation": "^3.40.0", "@aws-sdk/client-fms": "^3.43.0", "@aws-sdk/client-service-quotas": "^3.38.0", - "@aws-sdk/client-wafv2": "^3.35.0", + "@aws-sdk/client-wafv2": "^3.48.0", "@mhlabs/cfn-diagram": "^1.1.32", "@types/lodash": "^4.14.178", + "aws-cdk-lib": "^2.8.0", + "constructs": "^10.0.0", "lodash": "^4.17.21", "process": "^0.11.10", "shapes": "^0.4.0" diff --git a/values/calculatecapacity.json b/values/calculatecapacity.json index ea0fa0d6..885c55b4 100644 --- a/values/calculatecapacity.json +++ b/values/calculatecapacity.json @@ -1,11 +1,12 @@ { "Name": "TEST", "Priority": 0, -"Action": { - "Allow": {} -}, "Statement": { }, +"Action":{ +}, +"CaptchaConfig":{ +}, "VisibilityConfig": { "SampledRequestsEnabled": false, "CloudWatchMetricsEnabled": false,