Skip to content

Commit

Permalink
Merge pull request #11 from globaldatanet/Captcha-Action-support
Browse files Browse the repository at this point in the history
Captcha action support
  • Loading branch information
daknhh authored Jan 23, 2022
2 parents dc73833 + 82c5ed9 commit 7cb9b1b
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 61 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 38 additions & 15 deletions bin/plattform-wafv2-cdk-automation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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<number>{
let current_quota = 0
Expand Down Expand Up @@ -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 = {
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
111 changes: 72 additions & 39 deletions lib/plattform-wafv2-cdk-automation-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ interface RulesArray{
Name?: string,
Statement: any,
Action: any,
VisibilityConfig: any
VisibilityConfig: any,
CaptchaConfig?: any,
}

function toCamel(o: any) {
Expand Down Expand Up @@ -163,35 +164,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}"]
Expand Down Expand Up @@ -222,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),
Expand All @@ -232,7 +247,7 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack {
cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled,
metricName: rulename + "-metric",
},
};
};}
rules.push(CfnRuleProperty)
count +=1
}
Expand Down Expand Up @@ -410,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++
}
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
7 changes: 4 additions & 3 deletions values/calculatecapacity.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"Name": "TEST",
"Priority": 0,
"Action": {
"Allow": {}
},
"Statement": {
},
"Action":{
},
"CaptchaConfig":{
},
"VisibilityConfig": {
"SampledRequestsEnabled": false,
"CloudWatchMetricsEnabled": false,
Expand Down

0 comments on commit 7cb9b1b

Please sign in to comment.