diff --git a/CHANGELOG.md b/CHANGELOG.md
index b94e5839..65778d27 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,32 @@
# Change Log
## Released
+
+## 2.0.0
+
+### Added
+1. preProcessRuleGroups and postProcessRuleGroups - you can decide now where the Custom or ManagedRules should be added to.
+
+2. RuleLabels - A label is a string made up of a prefix, optional namespaces, and a name. The components of a label are delimited with a colon. Labels have the following requirements and characteristics:
+
+ - Labels are case-sensitive.
+
+ - Each label namespace or label name can have up to 128 characters.
+
+ - You can specify up to five namespaces in a label.
+
+ - Components of a label are separated by colon (:).
+### Changed
+
+1. Values Structure:
+
+ - Removed (Rules and ManagedRuleGroups)
+ - Added PreProcess and PostProcess
+
+โน๏ธ See [example json](./values/example-waf.json).
+
+2. Optimized RuleGroup Splitting - RuleGroups will now be splitted into Groups with up to 1000 WCU.
+
## 1.0.4
### Added
diff --git a/README.md b/README.md
index 988215e2..600e5c26 100644
--- a/README.md
+++ b/README.md
@@ -1,71 +1,99 @@
+# AWS FIREWALL FACTORY v2
+
[![License: Apache2](https://img.shields.io/badge/license-Apache%202-lightgrey.svg)](http://www.apache.org/licenses/) [![cdk](https://img.shields.io/badge/aws_cdk-v2-orange.svg)](https://docs.aws.amazon.com/cdk/v2/guide/home.html)
[![latest](https://img.shields.io/badge/latest-release-yellow.svg)](https://github.com/globaldatanet/aws-firewall-factory/releases)
+[![gdn](https://img.shields.io/badge/opensource-@globaldatanet-%2300ecbd)](https://globaldatanet.com/opensource) [![dakn](https://img.shields.io/badge/by-dakn-%23ae0009.svg)](https://github.com/daknhh)
-[![gdn](https://img.shields.io/badge/by-globaldatanet-%2300ecbd)](https://globaldatanet.com) [![dakn](https://img.shields.io/badge/by-dakn-%23ae0009.svg)](https://github.com/daknhh)
-
+
+AWS Web Application Firewalls (WAFs) protect web applications and APIs from typical attacks from the Internet that can compromise security and availability, and put undue strain on servers and resources. The AWS WAF provides prebuilt security rules that help control bot traffic and block attack patterns. However, with its help, you can also create your own rules based on your specific requirements. In simple scenarios and for smaller applications, this is very easy to implement on an individual basis. However, in larger environments with tens or even hundreds of applications, it is advisable to aim for central governance and automation. This simple solution helps you deploy, update, and stage your Web Application Firewalls while managing them centrally via AWS Firewall Manager
+
-# Web Application Firewalls at Scale
+- [AWS FIREWALL FACTORY](#aws-firewall-factory)
+ + [Media](#media)
+ * [Architecture](#architecture)
+ + [Prerequisites](#prerequisites-)
+ * [Features](#features)
+ + [Coming soon](#coming-soon-)
+ * [Deployment via Taskfile](#deployment-via-taskfile)
+ * [๐ Supporters](#---supporters)
-
-AWS Web Application Firewalls (WAFs) protect web applications and APIs from typical attacks from the Internet that can compromise security and availability, and put undue strain on servers and resources. The AWS WAF provides prebuilt security rules that help control bot traffic and block attack patterns. However, with its help, you can also create your own rules based on your specific requirements. In simple scenarios and for smaller applications, this is very easy to implement on an individual basis. However, in larger environments with tens or even hundreds of applications, it is advisable to aim for central governance and automation. This simple solution helps you deploy, update, and stage your Web Application Firewalls while managing them centrally via AWS Firewall Manager.
|Releases |Author |
--- | --- |
| [Changelog](CHANGELOG.md) - [Features](#Features)| David Krohn [Linkedin](https://www.linkedin.com/in/daknhh/) - [Blog](https://globaldatanet.com/our-team/david-krohn)|
+### Media
+If you want to learn something more about the AWS Firewall Factory feel free to look at the following media resources.
+- [๐บ Webinar: Web Application Firewalls at Scale](https://globaldatanet.com/webinars/aws-security-with-security-in-the-cloud)
+- [๐ Podcast coming soon](https://github.com/richarvey/aws-community-radio/issues/3)
## Architecture
![Architecture](./static/AWSFIREWALLMANAGER.png "Architecture")
-### Prerequisites:
+### Prerequisites
1. An central S3 Bucket with **write** permission for security account needs to be in place.
## Features
1. Automated Capactiy Calculation via [API - CheckCapacity](https://docs.aws.amazon.com/waf/latest/APIReference/API_CheckCapacity.html)
2. Algorithm to split Rules into RuleGroups
-3. Automated Update of RuleGroup if Capacity Changed
+3. Automated Update of RuleGroup if Capacity Changed
4. Add [ManagedRuleGroups](https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html) via configuration file
5. Automated Generation of draw.io [diagram](https://app.diagrams.net/) for each WAF
-6. Checking of the softlimit quota for WCU set in the AWS Account (Stop deployment if Caluclated WCU is above the quota)
+6. Checking of the softlimit quota for [WCU](https://docs.aws.amazon.com/waf/latest/developerguide/how-aws-waf-works.html) set in the AWS Account (Stop deployment if calculated WCU is above the quota)
7. Easy configuration of WAF Rules trough json file.
8. Deployment Hash to deploy same WAF more than one time for testing and/or blue/green deployments.
9. 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)**
-10. NEW **RegexMatchStatement** and **IPSetReferenceStatement** is working now ๐
-11. 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.
-12. 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.
-13. Added S3LoggingBucketName to json. You need to specify the S3 Bucket where the Logs should be placed in now. We also added a Prefix for the logs to be aws conform (Prefix: AWSLogs/AWS_ACCOUNTID/FirewallManager/AWS_REGION/).
+10. **RegexMatchStatement** and **IPSetReferenceStatement** is working now ๐
+11. You can 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.
+12. Support for Captcha - You can 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.
+13. Added S3LoggingBucketName to json. You need to specify the S3 Bucket where the Logs should be placed in now. We also added a Prefix for the logs to be aws conform (Prefix: AWSLogs/*AWS_ACCOUNTID*/FirewallManager/*AWS_REGION*/).
14. Added Testing your WAF with [GoTestWAF](https://github.com/wallarm/gotestwaf). To be able to check your waf we introduced the **SecuredDomain** Parameter in the json which should be your Domain which will be checked using the WAF tool.
-15. Introduced three new Parameters in the taskfile (**WAF_TEST**,**CREATE_DIAGRAM** and **CDK_DIFF**).
+15. TaskFileParameters:
| Parameter | Value |
|----------|:-------------:|
+| PROCESS_PARAMETERS | path to values file eg. values/example-waf.json |
+| SKIP_QUOTA_CHECK |true (Stop deployment if calculated WCU is above the quota) false (Skipping WCU Check) |
| WAF_TEST | true (testing your waf with GoTestWAF) false (Skipping WAF testing) |
| CREATE_DIAGRAM | true (generating a diagram using draw.io) false (Skipping diagram generation) |
| CDK_DIFF | true (generating a cdk before invoking cdk deploy) false (Skipping cdk diff) |
+
16. Validation of your ConfigFile using Schema validation - if you miss an required parameter in your config file the deployment will stop automatically and show you the missing path.
+17. PreProcess-and PostProcessRuleGroups - you can decide now where the Custom or ManagedRules should be added to.
+
+- New Structure see [example json](./values/example-waf.json).
+
+18. RuleLabels - A label is a string made up of a prefix, optional namespaces, and a name. The components of a label are delimited with a colon. Labels have the following requirements and characteristics:
+
+ - Labels are case-sensitive.
+
+ - Each label namespace or label name can have up to 128 characters.
+
+ - You can specify up to five namespaces in a label.
+ - Components of a label are separated by colon (:).
-## Coming soon:
+### Coming soon:
1. Deployment via Teamcity
-# Deployment via Taskfile
+## Deployment via Taskfile
0. Create new json file for you WAF and configure Rules in the JSON (see [example.json](values/example-waf.json) to see structure)
1. Set `PROCESS_PARAMETERS` in `Taskfile.yml` for new json file
2. Assume AWS Profile `awsume PROFILENAME`
3. Enter `task deploy`
-![Example Deployment](./static/example_deployment.jpg "Example Deployment")
+![Example Deployment](./static/example_deployment.png "Example Deployment")
### ๐ Supporters
diff --git a/Taskfile.yml b/Taskfile.yml
index df9af222..65748254 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -1,13 +1,17 @@
version: '3'
env:
PROCESS_PARAMETERS: values/example-waf.json
- CDK_DEFAULT_ACCOUNT: $(aws sts get-caller-identity |jq -r .Account)
- REGION: $(aws configure get profile.$AWSUME_PROFILE.region)
SKIP_QUOTA_CHECK: true
- WAF_TEST: true
+ WAF_TEST: false
CREATE_DIAGRAM: false
CDK_DIFF: false
+vars:
+ REGION:
+ sh: aws configure get profile.$AWSUME_PROFILE.region
+ CDK_DEFAULT_ACCOUNT:
+ sh: aws sts get-caller-identity |jq -r .Account
+
tasks:
deploy:
desc: Deploy Stack
diff --git a/bin/plattform-wafv2-cdk-automation.ts b/bin/plattform-wafv2-cdk-automation.ts
index 0ab1d45b..011d507e 100644
--- a/bin/plattform-wafv2-cdk-automation.ts
+++ b/bin/plattform-wafv2-cdk-automation.ts
@@ -13,8 +13,12 @@ import * as lodash from "lodash";
import { validate } from "../lib/tools/config-validator";
import {Config} from "../lib/types/config";
import { Runtimeprops } from "../lib/types/runtimeprops";
-
-const runtimeprops: Runtimeprops = {Capacity: 0, DeployedRuleGroupCapacities: [], RuleCapacities: [], DeployedRuleGroupNames: [], DeployedRuleGroupIdentifier: []}
+import * as awsfirewallfactoryinfo from "../package.json";
+const afwfver = awsfirewallfactoryinfo.version
+const runtimeprops: Runtimeprops = {PreProcessCapacity: 0, PostProcessCapacity: 0,
+ PreProcessDeployedRuleGroupCapacities: [], PreProcessRuleCapacities: [], PreProcessDeployedRuleGroupNames: [], PreProcessDeployedRuleGroupIdentifier: [],
+ PostProcessDeployedRuleGroupCapacities: [], PostProcessRuleCapacities: [], PostProcessDeployedRuleGroupNames: [], PostProcessDeployedRuleGroupIdentifier: []
+}
function str2ab(str: string): Uint8Array {
var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
@@ -153,17 +157,42 @@ async function GetOutputsFromStack(StackName:string,config: Config): Promise {
- if(!(indexes.find((e)=> e === i+1))){
- if(v+tracker <= threshold){
- tracker += v
- ruleset.push(i)
- indexes.push(i+1)
+ else{
+ const threshold = 1000
+ const rulesets: any[] = []
+ const indexes: number[] = []
+ const rulegroupcapacities = []
+ while(indexes.length {
+ if(!(indexes.find((e)=> e === i+1))){
+ if(v+tracker <= threshold){
+ tracker += v
+ ruleset.push(i)
+ indexes.push(i+1)
+ }
}
- }
- })
- rulesets.push(ruleset)
- rulegroupcapacities.push(tracker)
- }
+ })
+ rulesets.push(ruleset)
+ rulegroupcapacities.push(tracker)
+ }
- console.log(`๐ Split Rules into ${rulesets.length.toString()} RuleGroups \n โน๏ธ AWS Limitation 100 Capacity per RuleGroup\n`);
- let count = 0
- const preProcessRuleGroups = []
- let rulegroupidentifier = ""
- let name =""
- while (count < rulesets.length){
- if(typeof props.runtimeprops.DeployedRuleGroupCapacities[count] !== "undefined"){
- if(rulegroupcapacities[count] == props.runtimeprops.DeployedRuleGroupCapacities[count]){
- rulegroupidentifier = "R"+count.toString()
- name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash
- }
- else{
- console.log("\nโญ๏ธ Deploy new RuleGroup because the Capacity has changed for " +props.runtimeprops.DeployedRuleGroupIdentifier[count] + " !")
- console.log("\n ๐ฅ Old Capacity: ["+ props.runtimeprops.DeployedRuleGroupCapacities[count] + "]\n ๐ฉ New Capacity: [" + rulegroupcapacities[count] +"]")
- if(typeof props.runtimeprops.DeployedRuleGroupNames[count] !== "undefined"){
- if(props.runtimeprops.DeployedRuleGroupNames[count] == props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString()+ "-" +props.config.General.DeployHash){
- name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-R" + count.toString() + "-" +props.config.General.DeployHash
+ console.log(` ๐ Split Rules into ${rulesets.length.toString()} RuleGroups: \n`);
+ let count = 0
+ let rulegroupidentifier = ""
+ let name =""
+ while (count < rulesets.length){
+ if(typeof props.runtimeprops.PreProcessDeployedRuleGroupCapacities[count] !== "undefined"){
+ if(rulegroupcapacities[count] === props.runtimeprops.PreProcessDeployedRuleGroupCapacities[count]){
+ rulegroupidentifier = "preR"+count.toString()
+ name = props.config.WebAcl.Name + "-pre-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ else{
+ console.log("\nโญ๏ธ Deploy new RuleGroup because the Capacity has changed for " +props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[count] + " !")
+ console.log("\n ๐ฅ Old Capacity: ["+ props.runtimeprops.PreProcessDeployedRuleGroupCapacities[count] + "]\n ๐ฉ New Capacity: [" + rulegroupcapacities[count] +"]")
+ if(typeof props.runtimeprops.PreProcessDeployedRuleGroupCapacities[count] !== "undefined"){
+ if(props.runtimeprops.PreProcessDeployedRuleGroupNames[count] === props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString()+ "-" +props.config.General.DeployHash){
+ name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-preR-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ else{
+ name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-pre-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ console.log(" ๐ฌ New Name: "+ name)
}
- else{
- name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash
+ if(typeof props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[count] !== undefined){
+ if(props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[count] === "R"+count.toString()){
+ rulegroupidentifier = "preG"+count.toString()
+ }
+ else{
+ rulegroupidentifier = "preR"+count.toString()
+ }
+ console.log(" ๐ New Identifier: "+ rulegroupidentifier + "\n")
}
- console.log(" ๐ฌ New Name: "+ name)
}
- if(typeof props.runtimeprops.DeployedRuleGroupIdentifier[count] !== undefined){
- if(props.runtimeprops.DeployedRuleGroupIdentifier[count] == "R"+count.toString()){
- rulegroupidentifier = "G"+count.toString()
+ }else{
+ rulegroupidentifier = "preR"+count.toString()
+ name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ const CfnRuleProperties = []
+ let rulegroupcounter = 0
+ while( rulegroupcounter < rulesets[count].length){
+ const statementindex = rulesets[count][rulegroupcounter]
+ let rulename = ""
+ if(props.config.WebAcl.PreProcess.CustomRules[statementindex].Name !== undefined){
+ const Temp_Hash = Date.now().toString(36)
+ rulename = props.config.WebAcl.PreProcess.CustomRules[statementindex].Name + "-" + Temp_Hash
+ }
+ else{
+ rulename = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-pre-" + rulegroupcounter.toString() + "-" +props.config.General.DeployHash
+ }
+ let CfnRuleProperty
+ if("Captcha" in props.config.WebAcl.PreProcess.CustomRules[statementindex].Action){
+ CfnRuleProperty = {
+ name: rulename,
+ priority: rulegroupcounter,
+ action: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].Action),
+ statement: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].Statement),
+ visibilityConfig: {
+ sampledRequestsEnabled: props.config.WebAcl.PreProcess.CustomRules[statementindex].VisibilityConfig.SampledRequestsEnabled,
+ cloudWatchMetricsEnabled: props.config.WebAcl.PreProcess.CustomRules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled,
+ metricName: rulename + "-metric",
+ },
+ captchaConfig: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].CaptchaConfig),
+ ruleLabels: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].RuleLabels)
}
- else{
- rulegroupidentifier = "R"+count.toString()
+ }
+ else{
+ CfnRuleProperty = {
+ name: rulename,
+ priority: rulegroupcounter,
+ action: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].Action),
+ statement: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].Statement),
+ visibilityConfig: {
+ sampledRequestsEnabled: props.config.WebAcl.PreProcess.CustomRules[statementindex].VisibilityConfig.SampledRequestsEnabled,
+ cloudWatchMetricsEnabled: props.config.WebAcl.PreProcess.CustomRules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled,
+ metricName: rulename + "-metric",
+ },
+ ruleLabels: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].RuleLabels)
}
- console.log(" ๐ New Identifier: "+ rulegroupidentifier + "\n")
}
+ let CfnRuleProperti: wafv2.CfnRuleGroup.RuleProperty
+ if(props.config.WebAcl.PreProcess.CustomRules[statementindex].RuleLabels){
+ CfnRuleProperti = CfnRuleProperty
+ }
+ else{
+ const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty
+ CfnRuleProperti = CfnRulePropertii
+ }
+ CfnRuleProperties.push(CfnRuleProperti)
+ rulegroupcounter++
}
- }else{
- rulegroupidentifier = "R"+count.toString()
- name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash
+ new wafv2.CfnRuleGroup(this,rulegroupidentifier, {
+ capacity: rulegroupcapacities[count],
+ scope: props.config.WebAcl.Scope,
+ rules: CfnRuleProperties,
+ name: name,
+ visibilityConfig: {
+ sampledRequestsEnabled: false,
+ cloudWatchMetricsEnabled: false,
+ metricName: name + "-metric",
+ }
+ });
+
+ preProcessRuleGroups.push({"ruleGroupType":"RuleGroup","ruleGroupArn":"${"+ rulegroupidentifier +".Arn}","overrideAction":{"type":"NONE"}});
+ console.log(" โก๏ธ Creating " + rulegroupidentifier + " with calculated capacity: [" + rulegroupcapacities[count].toString() +"]")
+ props.runtimeprops.PreProcessDeployedRuleGroupCapacities[count] = rulegroupcapacities[count]
+ props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[count] = rulegroupidentifier
+ props.runtimeprops.PreProcessDeployedRuleGroupNames[count] = name
+ count++
}
- const CfnRuleProperties = []
- let rulegroupcounter = 0
- while( rulegroupcounter < rulesets[count].length){
- const statementindex = rulesets[count][rulegroupcounter]
+ const lenght = rulesets.length
+ props.runtimeprops.PreProcessDeployedRuleGroupCapacities.splice(lenght)
+ props.runtimeprops.PreProcessDeployedRuleGroupIdentifier.splice(lenght)
+ props.runtimeprops.PreProcessDeployedRuleGroupNames.splice(lenght)
+
+ new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupNames", {
+ value: props.runtimeprops.PreProcessDeployedRuleGroupNames.toString(),
+ description: "PreProcessDeployedRuleGroupNames",
+ exportName: "PreProcessDeployedRuleGroupNames"+props.config.General.DeployHash,
+ });
+
+ new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupCapacities", {
+ value: props.runtimeprops.PreProcessDeployedRuleGroupCapacities.toString(),
+ description: "PreProcessDeployedRuleGroupCapacities",
+ exportName: "PreProcessDeployedRuleGroupCapacities"+props.config.General.DeployHash,
+ });
+
+ new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupIdentifier", {
+ value: props.runtimeprops.PreProcessDeployedRuleGroupIdentifier.toString(),
+ description: "PreProcessDeployedRuleGroupIdentifier",
+ exportName: "PreProcessDeployedRuleGroupIdentifier"+props.config.General.DeployHash,
+ });
+ }
+ }
+ if(props.config.WebAcl.PostProcess.CustomRules === undefined){
+ console.log("\nโน๏ธ No Custom Rules defined in PostProcess.")
+ }
+ else{
+ console.log("\u001b[1m","\n๐ฅ Custom Rules PostProcess:","\x1b[0m\n")
+ if (props.runtimeprops.PostProcessCapacity < 1000){
+ const rules = [];
+ let count = 1
+
+ for(const statement of props.config.WebAcl.PostProcess.CustomRules){
let rulename = ""
- if(props.config.WebAcl.Rules[statementindex].Name !== undefined){
- const Temp_Hash = Date.now().toString(36)
- rulename = props.config.WebAcl.Rules[statementindex].Name + "-" + Temp_Hash
+ if(statement.Name !== undefined){
+ rulename = statement.Name + "-post-" + props.config.General.DeployHash
}
else{
- rulename = rulegroupcounter.toString()
+ rulename = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-post-" + count.toString() + "-" +props.config.General.DeployHash
}
- let CfnRuleProperty: wafv2.CfnRuleGroup.RuleProperty
- if("Captcha" in props.config.WebAcl.Rules[statementindex].Action){
+ let CfnRuleProperty
+ if("Captcha" in statement.Action){
CfnRuleProperty = {
name: rulename,
- priority: rulegroupcounter,
- action: toCamel(props.config.WebAcl.Rules[statementindex].Action),
- statement: toCamel(props.config.WebAcl.Rules[statementindex].Statement),
+ priority: count,
+ action: toCamel(statement.Action),
+ statement: toCamel(statement.Statement),
visibilityConfig: {
- sampledRequestsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.SampledRequestsEnabled,
- cloudWatchMetricsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled,
+ sampledRequestsEnabled: statement.VisibilityConfig.SampledRequestsEnabled,
+ cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled,
metricName: rulename + "-metric",
},
- captchaConfig: toCamel(props.config.WebAcl.Rules[statementindex].CaptchaConfig),
+ captchaConfig: toCamel(statement.CaptchaConfig),
+ ruleLabels: toCamel(statement.RuleLabels)
}
}
else{
CfnRuleProperty = {
name: rulename,
- priority: rulegroupcounter,
- action: toCamel(props.config.WebAcl.Rules[statementindex].Action),
- statement: toCamel(props.config.WebAcl.Rules[statementindex].Statement),
+ priority: count,
+ action: toCamel(statement.Action),
+ statement: toCamel(statement.Statement),
visibilityConfig: {
- sampledRequestsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.SampledRequestsEnabled,
- cloudWatchMetricsEnabled: props.config.WebAcl.Rules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled,
+ sampledRequestsEnabled: statement.VisibilityConfig.SampledRequestsEnabled,
+ cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled,
metricName: rulename + "-metric",
- }
- }
+ },
+ ruleLabels: toCamel(statement.RuleLabels)
+ };}
+ let CfnRuleProperti: wafv2.CfnRuleGroup.RuleProperty
+ if(statement.RuleLabels){
+ CfnRuleProperti = CfnRuleProperty
}
+ else{
+ const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty
+ CfnRuleProperti = CfnRulePropertii
+ }
+ rules.push(CfnRuleProperti)
+ count +=1
+ }
- CfnRuleProperties.push(CfnRuleProperty)
- rulegroupcounter++
+ let name = props.config.WebAcl.Name + "-post-" + props.config.General.Stage + "-" +props.config.General.DeployHash
+ let rulegroupidentifier = "PostRuleGroup"
+ if(typeof props.runtimeprops.PostProcessDeployedRuleGroupCapacities[0] !== "undefined"){
+ if(props.runtimeprops.PostProcessDeployedRuleGroupCapacities[0] !== props.runtimeprops.PostProcessCapacity){
+ console.log("โญ๏ธ Deploy new RuleGroup because the Capacity has changed!")
+ console.log("\n ๐ฅ Old Capacity: ["+ props.runtimeprops.PostProcessDeployedRuleGroupCapacities[0] + "]\n ๐ฉ New Capacity: [" + props.runtimeprops.PostProcessCapacity+"]")
+ if(props.runtimeprops.PostProcessDeployedRuleGroupIdentifier[0] === "PostRuleGroup"){
+ rulegroupidentifier ="postRG"
+ }
+ if(props.runtimeprops.PostProcessDeployedRuleGroupNames[0] === props.config.WebAcl.Name + "-post-" + props.config.General.Stage + "-" +props.config.General.DeployHash){
+ name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-postG-" +props.config.General.DeployHash
+ }
+ console.log(" ๐ฌ New Name: "+ name)
+ console.log(" ๐ New Identifier: "+ rulegroupidentifier)
+ }
}
- const rulegroup = new wafv2.CfnRuleGroup(this,rulegroupidentifier, {
- capacity: rulegroupcapacities[count],
+ new wafv2.CfnRuleGroup(this,rulegroupidentifier, {
+ capacity: props.runtimeprops.PostProcessCapacity,
scope: props.config.WebAcl.Scope,
- rules: CfnRuleProperties,
+ rules: rules,
name: name,
visibilityConfig: {
sampledRequestsEnabled: false,
cloudWatchMetricsEnabled: false,
- metricName: props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash,
+ metricName: name + "-metric",
}
});
+ postProcessRuleGroups.push({"ruleGroupType":"RuleGroup","ruleGroupArn":"${"+ rulegroupidentifier +".Arn}","overrideAction":{"type":"NONE"}});
+ console.log(" โก๏ธ Creating " + rulegroupidentifier + " with calculated capacity: [" + props.runtimeprops.PostProcessCapacity +"]")
+ props.runtimeprops.PostProcessDeployedRuleGroupCapacities.splice(0)
+ props.runtimeprops.PostProcessDeployedRuleGroupIdentifier.splice(0)
+ props.runtimeprops.PostProcessDeployedRuleGroupNames.splice(0)
+
+ props.runtimeprops.PostProcessDeployedRuleGroupIdentifier[0] = rulegroupidentifier
+ props.runtimeprops.PostProcessDeployedRuleGroupNames[0] = name
+ props.runtimeprops.PostProcessDeployedRuleGroupCapacities[0] = props.runtimeprops.PostProcessCapacity
+
+
+ new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupNames", {
+ value: props.runtimeprops.PostProcessDeployedRuleGroupNames.toString(),
+ description: "PostProcessDeployedRuleGroupNames",
+ exportName: "PostProcessDeployedRuleGroupNames"+props.config.General.DeployHash,
+ });
+
+ new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupCapacities", {
+ value: props.runtimeprops.PostProcessDeployedRuleGroupCapacities.toString(),
+ description: "PostProcessDeployedRuleGroupCapacities",
+ exportName: "PostProcessDeployedRuleGroupCapacities"+props.config.General.DeployHash,
+ });
+
+ new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupIdentifier", {
+ value: props.runtimeprops.PostProcessDeployedRuleGroupIdentifier.toString(),
+ description: "PostProcessDeployedRuleGroupIdentifier",
+ exportName: "PostProcessDeployedRuleGroupIdentifier"+props.config.General.DeployHash,
+ });
- preProcessRuleGroups.push({"ruleGroupType":"RuleGroup","ruleGroupArn":"${"+ rulegroupidentifier +".Arn}","overrideAction":{"type":"NONE"}});
- console.log(" โก๏ธ Creating " + rulegroupidentifier + " with calculated capacity: [" + rulegroupcapacities[count].toString() +"]")
- props.runtimeprops.DeployedRuleGroupCapacities[count] = rulegroupcapacities[count]
- props.runtimeprops.DeployedRuleGroupIdentifier[count] = rulegroupidentifier
- props.runtimeprops.DeployedRuleGroupNames[count] = name
- count++
}
- const lenght = rulesets.length
- props.runtimeprops.DeployedRuleGroupCapacities.splice(lenght)
- props.runtimeprops.DeployedRuleGroupIdentifier.splice(lenght)
- props.runtimeprops.DeployedRuleGroupNames.splice(lenght)
- const novalue = null
-
- new cdk.CfnOutput(this, "DeployedRuleGroupNames", {
- value: props.runtimeprops.DeployedRuleGroupNames.toString(),
- description: "DeployedRuleGroupNames",
- exportName: "DeployedRuleGroupNames"+props.config.General.DeployHash,
- });
+ else{
+ const threshold = 1000
+ const rulesets: any[] = []
+ const indexes: number[] = []
+ const rulegroupcapacities = []
+ while(indexes.length {
+ if(!(indexes.find((e)=> e === i+1))){
+ if(v+tracker <= threshold){
+ tracker += v
+ ruleset.push(i)
+ indexes.push(i+1)
+ }
+ }
+ })
+ rulesets.push(ruleset)
+ rulegroupcapacities.push(tracker)
+ }
- new cdk.CfnOutput(this, "DeployedRuleGroupCapacities", {
- value: props.runtimeprops.DeployedRuleGroupCapacities.toString(),
- description: "DeployedRuleGroupCapacities",
- exportName: "DeployedRuleGroupCapacities"+props.config.General.DeployHash,
- });
+ console.log(` ๐ Split Rules into ${rulesets.length.toString()} RuleGroups:\n`);
+ let count = 0
+ let rulegroupidentifier = ""
+ let name =""
+ while (count < rulesets.length){
+ if(typeof props.runtimeprops.PostProcessDeployedRuleGroupCapacities[count] !== "undefined"){
+ if(rulegroupcapacities[count] === props.runtimeprops.PostProcessDeployedRuleGroupCapacities[count]){
+ rulegroupidentifier = "postR"+count.toString()
+ name = props.config.WebAcl.Name + "-post-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ else{
+ console.log("\nโญ๏ธ Deploy new RuleGroup because the Capacity has changed for " +props.runtimeprops.PostProcessDeployedRuleGroupIdentifier[count] + " !")
+ console.log("\n ๐ฅ Old Capacity: ["+ props.runtimeprops.PostProcessDeployedRuleGroupCapacities[count] + "]\n ๐ฉ New Capacity: [" + rulegroupcapacities[count] +"]")
+ if(typeof props.runtimeprops.PostProcessDeployedRuleGroupCapacities[count] !== "undefined"){
+ if(props.runtimeprops.PostProcessDeployedRuleGroupNames[count] === props.config.WebAcl.Name + "-post-" + props.config.General.Stage + "-" + count.toString()+ "-" +props.config.General.DeployHash){
+ name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-postR-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ else{
+ name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-post-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ console.log(" ๐ฌ New Name: "+ name)
+ }
+ if(typeof props.runtimeprops.PostProcessDeployedRuleGroupIdentifier[count] !== undefined){
+ if(props.runtimeprops.PostProcessDeployedRuleGroupIdentifier[count] === "R"+count.toString()){
+ rulegroupidentifier = "postG"+count.toString()
+ }
+ else{
+ rulegroupidentifier = "postR"+count.toString()
+ }
+ console.log(" ๐ New Identifier: "+ rulegroupidentifier + "\n")
+ }
+ }
+ }else{
+ rulegroupidentifier = "postR"+count.toString()
+ name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-post-" + count.toString() + "-" +props.config.General.DeployHash
+ }
+ const CfnRuleProperties = []
+ let rulegroupcounter = 0
+ while( rulegroupcounter < rulesets[count].length){
+ const statementindex = rulesets[count][rulegroupcounter]
+ let rulename = ""
+ if(props.config.WebAcl.PostProcess.CustomRules[statementindex].Name !== undefined){
+ const Temp_Hash = Date.now().toString(36)
+ rulename = props.config.WebAcl.PostProcess.CustomRules[statementindex].Name + "-post-" + Temp_Hash
+ }
+ else{
+ rulename = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-post-" + rulegroupcounter.toString() + "-" +props.config.General.DeployHash
+ }
+ let CfnRuleProperty
+ if("Captcha" in props.config.WebAcl.PostProcess.CustomRules[statementindex].Action){
+ CfnRuleProperty = {
+ name: rulename,
+ priority: rulegroupcounter,
+ action: toCamel(props.config.WebAcl.PostProcess.CustomRules[statementindex].Action),
+ statement: toCamel(props.config.WebAcl.PostProcess.CustomRules[statementindex].Statement),
+ visibilityConfig: {
+ sampledRequestsEnabled: props.config.WebAcl.PostProcess.CustomRules[statementindex].VisibilityConfig.SampledRequestsEnabled,
+ cloudWatchMetricsEnabled: props.config.WebAcl.PostProcess.CustomRules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled,
+ metricName: rulename + "-metric",
+ },
+ captchaConfig: toCamel(props.config.WebAcl.PostProcess.CustomRules[statementindex].CaptchaConfig),
+ ruleLabels: toCamel(props.config.WebAcl.PostProcess.CustomRules[statementindex].RuleLabels)
+ }
+ }
+ else{
+ CfnRuleProperty = {
+ name: rulename,
+ priority: rulegroupcounter,
+ action: toCamel(props.config.WebAcl.PostProcess.CustomRules[statementindex].Action),
+ statement: toCamel(props.config.WebAcl.PostProcess.CustomRules[statementindex].Statement),
+ visibilityConfig: {
+ sampledRequestsEnabled: props.config.WebAcl.PostProcess.CustomRules[statementindex].VisibilityConfig.SampledRequestsEnabled,
+ cloudWatchMetricsEnabled: props.config.WebAcl.PostProcess.CustomRules[statementindex].VisibilityConfig.CloudWatchMetricsEnabled,
+ metricName: rulename + "-metric",
+ },
+ ruleLabels: toCamel(props.config.WebAcl.PostProcess.CustomRules[statementindex].RuleLabels)
+ }
+ }
+ let CfnRuleProperti: wafv2.CfnRuleGroup.RuleProperty
+ if(props.config.WebAcl.PostProcess.CustomRules[statementindex].RuleLabels){
+ const CfnRulePropertii = CfnRuleProperty
+ CfnRuleProperti = CfnRulePropertii
+ }
+ else{
+ const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty
+ CfnRuleProperti = CfnRulePropertii
+ }
+ CfnRuleProperties.push(CfnRuleProperti)
+ rulegroupcounter++
+ }
+ new wafv2.CfnRuleGroup(this,rulegroupidentifier, {
+ capacity: rulegroupcapacities[count],
+ scope: props.config.WebAcl.Scope,
+ rules: CfnRuleProperties,
+ name: name,
+ visibilityConfig: {
+ sampledRequestsEnabled: false,
+ cloudWatchMetricsEnabled: false,
+ metricName: props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash,
+ }
+ });
+
+ postProcessRuleGroups.push({"ruleGroupType":"RuleGroup","ruleGroupArn":"${"+ rulegroupidentifier +".Arn}","overrideAction":{"type":"NONE"}});
+ console.log(" โก๏ธ Creating " + rulegroupidentifier + " with calculated capacity: [" + rulegroupcapacities[count].toString() +"]")
+ props.runtimeprops.PostProcessDeployedRuleGroupCapacities[count] = rulegroupcapacities[count]
+ props.runtimeprops.PostProcessDeployedRuleGroupIdentifier[count] = rulegroupidentifier
+ props.runtimeprops.PostProcessDeployedRuleGroupNames[count] = name
+ count++
+ }
+ const lenght = rulesets.length
+ props.runtimeprops.PostProcessDeployedRuleGroupCapacities.splice(lenght)
+ props.runtimeprops.PostProcessDeployedRuleGroupIdentifier.splice(lenght)
+ props.runtimeprops.PostProcessDeployedRuleGroupNames.splice(lenght)
+
+ new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupNames", {
+ value: props.runtimeprops.PostProcessDeployedRuleGroupNames.toString(),
+ description: "PostProcessDeployedRuleGroupNames",
+ exportName: "PostProcessDeployedRuleGroupNames"+props.config.General.DeployHash,
+ });
- new cdk.CfnOutput(this, "DeployedRuleGroupIdentifier", {
- value: props.runtimeprops.DeployedRuleGroupIdentifier.toString(),
- description: "DeployedRuleGroupIdentifier",
- exportName: "DeployedRuleGroupIdentifier"+props.config.General.DeployHash,
- });
+ new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupIdentifier", {
+ value: props.runtimeprops.PostProcessDeployedRuleGroupIdentifier.toString(),
+ description: "PostProcessDeployedRuleGroupIdentifier",
+ exportName: "PostProcessDeployedRuleGroupIdentifier"+props.config.General.DeployHash,
+ });
+ new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupCapacities", {
+ value: props.runtimeprops.PostProcessDeployedRuleGroupCapacities.toString(),
+ description: "PostProcessDeployedRuleGroupCapacities",
+ exportName: "PostProcessDeployedRuleGroupCapacities"+props.config.General.DeployHash,
+ });
+ }
+ }
+ const novalue = null
+ if(props.config.WebAcl.PostProcess.ManagedRuleGroups === undefined){
+ console.log("\nโน๏ธ No ManagedRuleGroups defined in PostProcess.")
+ }
+ else{
let mangedrule;
- let ExcludeRules;
- let OverrideAction;
- for(mangedrule of props.config.WebAcl.ManagedRuleGroups){
+ for(mangedrule of props.config.WebAcl.PostProcess.ManagedRuleGroups){
+ let ExcludeRules;
+ let OverrideAction;
if(mangedrule.ExcludeRules){
ExcludeRules = toCamel(mangedrule.ExcludeRules)
OverrideAction = mangedrule.OverrideAction
@@ -487,16 +733,43 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack {
ExcludeRules = []
OverrideAction = { "type": "NONE" }
}
- if(mangedrule.Version == ""){
- preProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor,
+ if(mangedrule.Version === ""){
+ postProcessRuleGroups.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,
+ postProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor,
"managedRuleGroupName":mangedrule.Name,"version": mangedrule.Version},"overrideAction": OverrideAction,
"ruleGroupArn": novalue,"excludeRules": ExcludeRules,"ruleGroupType": "ManagedRuleGroup"});}
}
-
+ }
+ if(props.config.WebAcl.PreProcess.ManagedRuleGroups === undefined){
+ console.log("โน๏ธ No ManagedRuleGroups defined in PreProcess.")
+ }
+ else{
+ let mangedrule;
+ for(mangedrule of props.config.WebAcl.PreProcess.ManagedRuleGroups){
+ let PreProcessExcludeRules = [];
+ let OverrideAction;
+ if(mangedrule.ExcludeRules){
+ PreProcessExcludeRules = toCamel(mangedrule.ExcludeRules)
+ OverrideAction = mangedrule.OverrideAction
+ }
+ else{
+ PreProcessExcludeRules = []
+ OverrideAction = { "type": "NONE" }
+ }
+ if(mangedrule.Version === ""){
+ preProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor,
+ "managedRuleGroupName":mangedrule.Name,"version": novalue},"overrideAction": OverrideAction,
+ "ruleGroupArn": novalue,"excludeRules": PreProcessExcludeRules,"ruleGroupType": "ManagedRuleGroup"});}
+ else{
+ preProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor,
+ "managedRuleGroupName":mangedrule.Name,"version": mangedrule.Version},"overrideAction": OverrideAction,
+ "ruleGroupArn": novalue,"excludeRules": PreProcessExcludeRules,"ruleGroupType": "ManagedRuleGroup"});}
+ }
+ }
+ if(postProcessRuleGroups === []){
const securityservicepolicydata = {
"type":"WAFV2",
"defaultAction":{ "type":"ALLOW" },
@@ -507,7 +780,47 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack {
"logDestinationConfigs":["${S3DeliveryStream.Arn}"]
}
}
- const fmsPolicy = new fms.CfnPolicy(this, "CfnPolicy", {
+ new fms.CfnPolicy(this, "CfnPolicy", {
+ excludeResourceTags: false,
+ remediationEnabled: false,
+ resourceType: props.config.WebAcl.Type,
+ policyName: props.config.General.Prefix.toUpperCase() + "-" + props.config.WebAcl.Name + "-" + props.config.General.Stage+ "-" +props.config.General.DeployHash,
+ includeMap: {account: props.config.General.DeployTo },
+ securityServicePolicyData: {"Type": "WAFV2","ManagedServiceData": cdk.Fn.sub(JSON.stringify(securityservicepolicydata))}
+ });
+ }
+ if(preProcessRuleGroups === []){
+ const securityservicepolicydata = {
+ "type":"WAFV2",
+ "defaultAction":{ "type":"ALLOW" },
+ "preProcessRuleGroups": [],
+ "postProcessRuleGroups": postProcessRuleGroups,
+ "overrideCustomerWebACLAssociation":true,
+ "loggingConfiguration": {
+ "logDestinationConfigs":["${S3DeliveryStream.Arn}"]
+ }
+ }
+ new fms.CfnPolicy(this, "CfnPolicy", {
+ excludeResourceTags: false,
+ remediationEnabled: false,
+ resourceType: props.config.WebAcl.Type,
+ policyName: props.config.General.Prefix.toUpperCase() + "-" + props.config.WebAcl.Name + "-" + props.config.General.Stage+ "-" +props.config.General.DeployHash,
+ includeMap: {account: props.config.General.DeployTo },
+ securityServicePolicyData: {"Type": "WAFV2","ManagedServiceData": cdk.Fn.sub(JSON.stringify(securityservicepolicydata))}
+ });
+ }
+ if(preProcessRuleGroups !== [] && postProcessRuleGroups !== []){
+ const securityservicepolicydata = {
+ "type":"WAFV2",
+ "defaultAction":{ "type":"ALLOW" },
+ "preProcessRuleGroups": preProcessRuleGroups,
+ "postProcessRuleGroups": postProcessRuleGroups,
+ "overrideCustomerWebACLAssociation":true,
+ "loggingConfiguration": {
+ "logDestinationConfigs":["${S3DeliveryStream.Arn}"]
+ }
+ }
+ new fms.CfnPolicy(this, "CfnPolicy", {
excludeResourceTags: false,
remediationEnabled: false,
resourceType: props.config.WebAcl.Type,
@@ -519,10 +832,11 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack {
}
const options = { flag : "w", force: true };
- const { promises: fsp } = require("fs");
(async () => {
try {
- await fsp.writeFile(process.env.PROCESS_PARAMETERS,JSON.stringify(props.config,null,2),options);
+ if (process.env.PROCESS_PARAMETERS) {
+ await fsp.writeFile(process.env.PROCESS_PARAMETERS,JSON.stringify(props.config,null,2),options);
+ }
} catch (error) {
console.log("Error " + error)
}
diff --git a/lib/tools/camel-case.ts b/lib/tools/camel-case.ts
new file mode 100644
index 00000000..be7d4423
--- /dev/null
+++ b/lib/tools/camel-case.ts
@@ -0,0 +1,39 @@
+export function toCamel(o: any) {
+ let newO: any, origKey: any, newKey: any, value: any
+ if (o instanceof Array) {
+ return o.map(function(value) {
+ if (typeof value === "object") {
+ value = toCamel(value)
+ }
+ if(value === "aRN"){
+ value = "arn"
+ }
+ if(value === "iPSetReferenceStatement"){
+ value = "ipSetReferenceStatement"
+ }
+ return value
+ })
+ } else {
+ newO = {}
+ for (origKey in o) {
+ if (Object.prototype.hasOwnProperty.call(o, origKey)) {
+ newKey = (origKey.charAt(0).toLowerCase() + origKey.slice(1) || origKey).toString()
+ if(newKey === "aRN"){
+ newKey = "arn"
+ }
+ if(newKey === "iPSetReferenceStatement"){
+ newKey = "ipSetReferenceStatement"
+ }
+ value = o[origKey]
+ if (value instanceof Array || (value !== null && value.constructor === Object)) {
+ value = toCamel(value)
+ if(value === "aRN"){
+ value = "arn"
+ }
+ }
+ newO[newKey] = value
+ }
+ }
+ }
+ return newO
+}
\ No newline at end of file
diff --git a/lib/types/config.ts b/lib/types/config.ts
index 7f99815e..4fc4eef8 100644
--- a/lib/types/config.ts
+++ b/lib/types/config.ts
@@ -1,3 +1,11 @@
+interface RulesArray{
+ Name?: string,
+ Statement: any,
+ Action: any,
+ VisibilityConfig: any,
+ CaptchaConfig?: any,
+}
+
export interface Config {
readonly General: {
readonly Prefix: string,
@@ -12,15 +20,23 @@ export interface Config {
readonly Name: string,
readonly Scope: string,
readonly Type: string,
- readonly Rules: Array,
- readonly ManagedRuleGroups: any[],
+ readonly PreProcess: {
+ CustomRules?: Array | undefined,
+ ManagedRuleGroups?: any[] | undefined;
+ }
+ readonly PostProcess:{
+ CustomRules?: Array | undefined,
+ ManagedRuleGroups?: any[] | undefined;
+ }
},
}
+
interface RulesArray{
Name?: string,
Statement: any,
Action: any,
VisibilityConfig: any,
CaptchaConfig?: any,
+ RuleLabels?: any
}
\ No newline at end of file
diff --git a/lib/types/runtimeprops.ts b/lib/types/runtimeprops.ts
index e80771a4..7f08e2af 100644
--- a/lib/types/runtimeprops.ts
+++ b/lib/types/runtimeprops.ts
@@ -1,7 +1,12 @@
export interface Runtimeprops {
- Capacity: number,
- RuleCapacities: number[],
- DeployedRuleGroupCapacities: number[],
- DeployedRuleGroupNames: string[],
- DeployedRuleGroupIdentifier: string[]
+ PreProcessCapacity: number,
+ PostProcessCapacity: number,
+ PreProcessRuleCapacities: number[],
+ PostProcessRuleCapacities: number[],
+ PreProcessDeployedRuleGroupCapacities: number[],
+ PreProcessDeployedRuleGroupNames: string[],
+ PreProcessDeployedRuleGroupIdentifier: string[],
+ PostProcessDeployedRuleGroupCapacities: number[],
+ PostProcessDeployedRuleGroupNames: string[],
+ PostProcessDeployedRuleGroupIdentifier: string[],
}
\ No newline at end of file
diff --git a/package.json b/package.json
index d3f2385e..2b95ef83 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "plattform-wafv2-cdk-automation",
- "version": "0.1.0",
+ "version": "2.0.0",
"bin": {
"plattform-wafv2-cdk-automation": "bin/plattform-wafv2-cdk-automation.js"
},
@@ -27,7 +27,6 @@
"typescript": "~3.9.7"
},
"dependencies": {
- "typescript-json-schema": "^0.53.0",
"@aws-sdk/client-cloudformation": "^3.40.0",
"@aws-sdk/client-fms": "^3.43.0",
"@aws-sdk/client-service-quotas": "^3.38.0",
@@ -38,6 +37,7 @@
"constructs": "^10.0.0",
"lodash": "^4.17.21",
"process": "^0.11.10",
- "shapes": "^0.4.0"
+ "shapes": "^0.4.0",
+ "typescript-json-schema": "^0.53.0"
}
}
diff --git a/static/example_deployment.jpg b/static/example_deployment.jpg
deleted file mode 100644
index bcc7638d..00000000
Binary files a/static/example_deployment.jpg and /dev/null differ
diff --git a/static/example_deployment.png b/static/example_deployment.png
new file mode 100644
index 00000000..481c3f07
Binary files /dev/null and b/static/example_deployment.png differ
diff --git a/static/icon/firewallfactory.svg b/static/icon/firewallfactory.svg
index 905ba1d8..7d374bbf 100644
--- a/static/icon/firewallfactory.svg
+++ b/static/icon/firewallfactory.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/values/calculatecapacity.json b/values/calculatecapacity.json
index 885c55b4..749981e2 100644
--- a/values/calculatecapacity.json
+++ b/values/calculatecapacity.json
@@ -11,5 +11,6 @@
"SampledRequestsEnabled": false,
"CloudWatchMetricsEnabled": false,
"MetricName": "TEST"
- }
+},
+"RuleLabels": []
}
diff --git a/values/example-waf.json b/values/example-waf.json
index e362d6cf..64aec096 100644
--- a/values/example-waf.json
+++ b/values/example-waf.json
@@ -1,140 +1,131 @@
{
- "General": {
- "Prefix": "gdn",
- "Stage": "int",
- "DeployTo": [
- ""
- ],
- "S3LoggingBucketName": "",
- "FireHoseKeyArn": "",
- "DeployHash": "",
- "SecuredDomain":""
- },
- "WebAcl": {
- "Name": "DAVID",
- "Scope": "REGIONAL",
- "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
- "Rules": [
- {
- "Statement": {
- "AndStatement": {
- "Statements": [
- {
- "ByteMatchStatement": {
- "SearchString": "test.de",
- "FieldToMatch": {
- "SingleHeader": {
- "Name": "host"
- }
- },
- "TextTransformations": [
- {
- "Priority": 0,
- "Type": "NONE"
- }
- ],
- "PositionalConstraint": "CONTAINS"
- }
- },
- {
- "ByteMatchStatement": {
- "SearchString": "test.de",
- "FieldToMatch": {
- "SingleHeader": {
- "Name": "host"
- }
- },
- "TextTransformations": [
- {
- "Priority": 0,
- "Type": "NONE"
- }
- ],
- "PositionalConstraint": "CONTAINS"
- }
- }
- ]
- }
- },
- "Action": {
- "Allow": {}
- },
- "VisibilityConfig": {
- "SampledRequestsEnabled": true,
- "CloudWatchMetricsEnabled": true
- }
- },
- {
- "Statement": {
- "OrStatement": {
- "Statements": [
- {
- "RegexMatchStatement": {
- "RegexString": "^.*\\/clients-registrations\\/openid-connect",
- "FieldToMatch": {
- "UriPath": {}
- },
- "TextTransformations": [
- {
- "Priority": 0,
- "Type": "LOWERCASE"
- }
- ]
- }
- },
- {
- "RegexMatchStatement": {
- "RegexString": "^.*\\/console",
- "FieldToMatch": {
- "UriPath": {}
- },
- "TextTransformations": [
- {
- "Priority": 0,
- "Type": "LOWERCASE"
- }
- ]
- }
- }
- ]
- }
- },
- "Action": {
- "Block": {}
- },
- "VisibilityConfig": {
- "SampledRequestsEnabled": true,
- "CloudWatchMetricsEnabled": true
- }
- },
- ],
- "ManagedRuleGroups": [
- {
- "Vendor": "AWS",
- "Name": "AWSManagedRulesCommonRuleSet",
- "ExcludeRules": [
- {
- "Name": "CrossSiteScripting_BODY"
- },
- {
- "Name": "GenericRFI_QUERYARGUMENTS"
- },
- {
- "Name": "NoUserAgent_HEADER"
- }
- ],
- "Version": "",
- "OverrideAction": {
- "type": "COUNT"
- },
- "Capacity": 700
- },
- {
- "Vendor": "AWS",
- "Name": "AWSManagedRulesAmazonIpReputationList",
- "Version": "",
- "Capacity": 25
- }
- ]
- }
+ "General": {
+ "Prefix": "gdn",
+ "Stage": "int",
+ "DeployTo": [
+ ""
+ ],
+ "S3LoggingBucketName": "",
+ "FireHoseKeyArn": "",
+ "DeployHash": "",
+ "SecuredDomain": ""
+ },
+ "WebAcl": {
+ "Name": "DAVID",
+ "Scope": "REGIONAL",
+ "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
+ "PreProcess": {
+ "ManagedRuleGroups": [{
+ "Vendor": "AWS",
+ "Name": "AWSManagedRulesCommonRuleSet",
+ "ExcludeRules": [{
+ "Name": "CrossSiteScripting_BODY"
+ },
+ {
+ "Name": "GenericRFI_QUERYARGUMENTS"
+ },
+ {
+ "Name": "NoUserAgent_HEADER"
+ }
+ ],
+ "Version": "",
+ "OverrideAction": {
+ "type": "COUNT"
+ },
+ "Capacity": 700
+ }
+ ]
+ },
+ "PostProcess": {
+ "CustomRules": [{
+ "Statement": {
+ "AndStatement": {
+ "Statements": [{
+ "ByteMatchStatement": {
+ "SearchString": "test.de",
+ "FieldToMatch": {
+ "SingleHeader": {
+ "Name": "host"
+ }
+ },
+ "TextTransformations": [{
+ "Priority": 0,
+ "Type": "NONE"
+ }],
+ "PositionalConstraint": "CONTAINS"
+ }
+ },
+ {
+ "ByteMatchStatement": {
+ "SearchString": "test.de",
+ "FieldToMatch": {
+ "SingleHeader": {
+ "Name": "host"
+ }
+ },
+ "TextTransformations": [{
+ "Priority": 0,
+ "Type": "NONE"
+ }],
+ "PositionalConstraint": "CONTAINS"
+ }
+ }
+ ]
+ }
+ },
+ "Action": {
+ "Allow": {}
+ },
+ "VisibilityConfig": {
+ "SampledRequestsEnabled": true,
+ "CloudWatchMetricsEnabled": true
+ }
+ },
+ {
+ "Statement": {
+ "OrStatement": {
+ "Statements": [{
+ "RegexMatchStatement": {
+ "RegexString": "^.*\\/clients-registrations\\/openid-connect",
+ "FieldToMatch": {
+ "UriPath": {}
+ },
+ "TextTransformations": [{
+ "Priority": 0,
+ "Type": "LOWERCASE"
+ }]
+ }
+ },
+ {
+ "RegexMatchStatement": {
+ "RegexString": "^.*\\/console",
+ "FieldToMatch": {
+ "UriPath": {}
+ },
+ "TextTransformations": [{
+ "Priority": 0,
+ "Type": "LOWERCASE"
+ }]
+ }
+ }
+ ]
+ }
+ },
+ "Action": {
+ "Block": {}
+ },
+ "VisibilityConfig": {
+ "SampledRequestsEnabled": true,
+ "CloudWatchMetricsEnabled": true
+ }
+ }
+ ],
+ "ManagedRuleGroups":[{
+ "Vendor": "AWS",
+ "Name": "AWSManagedRulesAmazonIpReputationList",
+ "Version": "",
+ "Capacity": 25
+ }]
+ }
+ }
}
\ No newline at end of file