From ab2f89f3adab2efe0dc874fe343722cf6b608c28 Mon Sep 17 00:00:00 2001 From: Marcell Jobs <31279340+kirnberger1980@users.noreply.github.com> Date: Thu, 24 Feb 2022 18:41:34 +0100 Subject: [PATCH 1/4] Introduce Linting & Refactoring (Part 1) - Added Linting with typescript-eslint - Added .gitignore and .npmignore file - Refactoring bin file: outsource capacity checks & other functions to helpers.ts - Transform capacity.json to Typescript Type Rule - Start refactoring lib file: get rid of redundant code and use JS shortcuts - Extend types of the Config interface --- .eslintignore | 3 + .eslintrc | 45 + .gitignore | 10 + .npmignore | 6 + Taskfile.yml | 7 +- bin/plattform-wafv2-cdk-automation.ts | 416 +---- lib/plattform-wafv2-cdk-automation-stack.ts | 1633 ++++++++++++------- lib/tools/camel-case.ts | 39 - lib/tools/helpers.ts | 529 ++++++ lib/types/config.ts | 69 +- lib/types/runtimeprops.ts | 3 +- package.json | 10 +- values/calculatecapacity.json | 16 - 13 files changed, 1776 insertions(+), 1010 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc create mode 100644 .gitignore create mode 100644 .npmignore delete mode 100644 lib/tools/camel-case.ts create mode 100644 lib/tools/helpers.ts delete mode 100644 values/calculatecapacity.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..5035c46c --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules +dist +cdk.out \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..7943b508 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,45 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "semi": [2, "always"], + "eqeqeq": 2, + "indent": [2, 2, {"SwitchCase": 1}], + "quotes": ["error", "double"], + "linebreak-style": "off", + "array-bracket-newline": "off", + "array-bracket-spacing": ["error", "never"], + "no-trailing-spaces": "off", + "padded-blocks": "off", + "arrow-body-style": "off", + "init-declarations": "off", + "comma-dangle": "off", + "keyword-spacing": [0, {"before": true, "after": true, "overrides": null}], + "prefer-template": "off", + "id-blacklist": "off", + "no-console": "off", + "no-sync": "off", + "complexity": "off", + "max-statements": "off", + "array-element-newline": "off", + "object-curly-spacing": "off", + "template-curly-spacing": "off", + "camelcase": "off", + "no-use-before-define": "off", + "id-length": "off", + "id-match": "off", + "max-len": "off", + "no-magic-numbers": "off", + "no-underscore-dangle": "off", + "no-process-env": "off", + "func-style": ["error", "declaration", { "allowArrowFunctions": true }] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..bd81d818 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.js +!jest.config.js +*.d.ts +node_modules + +# CDK asset staging directory +.cdk.staging +cdk.out +cdk.context.json +package-lock.json \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..c1d6d45d --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +*.ts +!*.d.ts + +# CDK asset staging directory +.cdk.staging +cdk.out diff --git a/Taskfile.yml b/Taskfile.yml index 65748254..fddf786b 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -67,4 +67,9 @@ tasks: silent: true preconditions: - sh: if [[ {{.WAF_TEST}} = true ]] ; then exit 0; else exit 1; fi - msg: โญ Skipping WAF Testing ๐Ÿงช \ No newline at end of file + msg: โญ Skipping WAF Testing ๐Ÿงช + validateconfig: + desc: Validation of the current config + cmds: + - ts-node test/config-loader.ts + silent: true \ No newline at end of file diff --git a/bin/plattform-wafv2-cdk-automation.ts b/bin/plattform-wafv2-cdk-automation.ts index 011d507e..14aa1756 100644 --- a/bin/plattform-wafv2-cdk-automation.ts +++ b/bin/plattform-wafv2-cdk-automation.ts @@ -1,398 +1,102 @@ #!/usr/bin/env node import { PlattformWafv2CdkAutomationStack } from "../lib/plattform-wafv2-cdk-automation-stack"; import * as cdk from "aws-cdk-lib"; -import * as fs from "fs"; -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"; -import { exit, off, prependOnceListener } from "process"; -import * as template from "../values/calculatecapacity.json"; -import { print } from "util"; -import * as lodash from "lodash"; +import { realpathSync, existsSync } from "fs"; import { validate } from "../lib/tools/config-validator"; -import {Config} from "../lib/types/config"; -import { Runtimeprops } from "../lib/types/runtimeprops"; -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: [] -} +import { Config } from "../lib/types/config"; +import { isPolicyQuotaReached, isWcuQuotaReached, setOutputsFromStack, initRuntimeProperties } from "../lib/tools/helpers"; +import * as packageJsonObject from "../package.json"; -function str2ab(str: string): Uint8Array { - var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char - var bufView = new Uint8Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return bufView; -} +/** + * Version of the AWS Firewall Factory - extracted from package.json + */ +const FIREWALL_FACTORY_VERSION = packageJsonObject.version; -function convertRules(o: any) { - var newO: any, origKey: any, value: any - if (o instanceof Array) { - return o.map(function (value) { - if (typeof value === "object") { - value = convertRules(value) - } - return value - }) - } else { - newO = {} - for (origKey in o) { - if (o.hasOwnProperty(origKey)) { - value = o[origKey] - if (value instanceof Array || (value !== null && value.constructor === Object)) { - value = convertRules(value) - } - if (origKey == "SearchString") { - value = str2ab(o[origKey]) - } - newO[origKey] = value - } - } - } - return newO -} - -async function ListPolicies(): Promise { - const client = new FMSClient({ region: deploymentregion }); - const input: ListPoliciesCommandInput = { - }; - const command = new ListPoliciesCommand(input); - const response = await client.send(command); - return response.PolicyList?.length || 0 -} - -async function CheckCapacity(Scope: string, calculated_capacity_json: object): Promise { - const client = new WAFV2Client({ region: deploymentregion }); - const newRules = convertRules(calculated_capacity_json) - const input: CheckCapacityCommandInput = { - Scope: Scope, - Rules: newRules - }; - const command = new CheckCapacityCommand(input); - const response: any = await client.send(command); - return response.Capacity | 0 -} -async function CheckQuota(Quoata: string): Promise{ - let current_quota = 0 - const quoata_client = new quota.ServiceQuotasClient({ region: deploymentregion }); - const input: quota.GetAWSDefaultServiceQuotaCommandInput = { - QuotaCode: Quoata, - ServiceCode: "fms" - }; - const command = new quota.GetAWSDefaultServiceQuotaCommand(input); - const responsequoata = await quoata_client.send(command); - if(responsequoata.Quota?.Adjustable == true){ - const input: quota.ListRequestedServiceQuotaChangeHistoryByQuotaCommandInput = { - QuotaCode: Quoata, - ServiceCode: "fms" - }; - const command = new quota.ListRequestedServiceQuotaChangeHistoryByQuotaCommand(input); - const newquota = await quoata_client.send(command); - if(newquota.RequestedQuotas != []){ - if(newquota.RequestedQuotas?.length || 0 == 0){ - const sortquota = lodash.sortBy(newquota.RequestedQuotas,["Created"]); - if(sortquota?.length == 1){ - if(sortquota?.[0].Status != "APPROVED"){ - console.log("โ„น๏ธ There is an open Quota request for " + Quoata + " but it is still not approved using DEFAULT Quota.") - current_quota = responsequoata.Quota?.Value || 0 - return current_quota - } - if(sortquota?.[0].Status == "APPROVED"){ - current_quota = sortquota?.[0].DesiredValue || 0 - return current_quota - } - } - } - else{ - current_quota = responsequoata.Quota?.Value || 0 - return current_quota - } - } - else{ - current_quota = responsequoata.Quota?.Value || 0 - return current_quota - } - } - current_quota = responsequoata.Quota?.Value || 0 - return current_quota -} - -async function GetManagedRuleCapacity(Vendor: string, Name: string, Scope: string, Version: string): Promise{ - const client = new WAFV2Client({ region: deploymentregion }); - if(Version == ""){ - const input: DescribeManagedRuleGroupCommandInput = { - VendorName: Vendor, - Name: Name, - Scope: Scope - } - const command = new DescribeManagedRuleGroupCommand(input); - const response: any = await client.send(command); - return response.Capacity | 0 - } - else{ - const input: DescribeManagedRuleGroupCommandInput = { - VendorName: Vendor, - Name: Name, - Scope: Scope, - VersionName: Version - } - const command = new DescribeManagedRuleGroupCommand(input); - const response: any = await client.send(command); - return response.Capacity | 0 - } -} +/** + * relative path to config file imported from the env PROCESS_PARAMETERS + */ +const configFile = process.env.PROCESS_PARAMETERS; -async function GetOutputsFromStack(StackName:string,config: Config): Promise{ - const cloudformation_client = new cloudformation.CloudFormationClient({ region: deploymentregion }); - const params ={ - StackName: StackName - } - const command = new cloudformation.DescribeStacksCommand(params); - const responsestack = await cloudformation_client.send(command); - if(responsestack.Stacks?.[0].StackName !== undefined && responsestack.Stacks?.[0].Outputs !== undefined){ - for(const output of responsestack.Stacks?.[0].Outputs){ - if(output.OutputKey == "DeployedRuleGroupNames") - { - runtimeprops.PreProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || [] - } - else if(output.OutputKey == "DeployedRuleGroupIdentifier") - { - runtimeprops.PreProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || [] - } - else if(output.OutputKey == "DeployedRuleGroupCapacities") - { - const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; - runtimeprops.PreProcessDeployedRuleGroupCapacities = arrayOfNumbers - } - if(output.OutputKey == "PreProcessDeployedRuleGroupNames") - { - runtimeprops.PreProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || [] - } - else if(output.OutputKey == "PreProcessDeployedRuleGroupIdentifier") - { - runtimeprops.PreProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || [] - } - else if(output.OutputKey == "PreProcessDeployedRuleGroupCapacities") - { - const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; - runtimeprops.PreProcessDeployedRuleGroupCapacities = arrayOfNumbers - } - if(output.OutputKey == "PostProcessDeployedRuleGroupNames") - { - runtimeprops.PostProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || [] - } - else if(output.OutputKey == "PostProcessDeployedRuleGroupIdentifier") - { - runtimeprops.PostProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || [] - } - else if(output.OutputKey == "PostProcessDeployedRuleGroupCapacities") - { - const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; - runtimeprops.PostProcessDeployedRuleGroupCapacities = arrayOfNumbers - } - } - } -} +/** + * the region into which the stack is deployed + */ +let deploymentRegion = ""; -// Export to Outputs Capacity Names etc. -let deploymentregion = "" -const configFile = process.env.PROCESS_PARAMETERS; -if (configFile && fs.existsSync(configFile)) { - const config: Config = require(fs.realpathSync(configFile)); +if (configFile && existsSync(configFile)) { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const config: Config = require(realpathSync(configFile)); if (validate(config)){ - const app = new cdk.App(); - runtimeprops.PostProcessRuleCapacities = [] - runtimeprops.PreProcessRuleCapacities = [] - let Temp_Hash - if(config.WebAcl.Scope == "CLOUDFRONT"){ - deploymentregion = "us-east-1" + if(config.WebAcl.Scope === "CLOUDFRONT"){ + deploymentRegion = "us-east-1"; } else{ - deploymentregion = process.env.REGION || "eu-central-1" + deploymentRegion = process.env.REGION || "eu-central-1"; } console.log(` โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ• - โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• - โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•šโ–ˆโ–ˆโ•”โ• - โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ - โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• + โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• + โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•šโ–ˆโ–ˆโ•”โ• + โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ + โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• `); console.log("\x1b[36m","\n by globaldatanet","\x1b[0m"); - console.log("\n๐Ÿท Version: ","\x1b[4m",afwfver,"\x1b[0m") + console.log("\n๐Ÿท Version: ","\x1b[4m",FIREWALL_FACTORY_VERSION,"\x1b[0m"); console.log("๐Ÿ‘ค 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 - console.log("#๏ธโƒฃ Generated Deployment Hash for this WAF: "+ config.General.DeployHash) - } - else{ - console.log("#๏ธโƒฃ Deployment Hash for this WAF: "+ config.General.DeployHash) - } - console.log("๐Ÿ”ฅ Deploy FMS Policy: " + config.General.Prefix.toUpperCase() + "-" + config.WebAcl.Name.toUpperCase()+ "-" + config.General.Stage + "-" + config.General.DeployHash + "\n โฆ‚ Type: " +config.WebAcl.Type + "\n๐Ÿ“š Stackname: " + config.General.Prefix.toUpperCase() + "-WAF-" + config.WebAcl.Name.toUpperCase() +"-"+config.General.Stage.toUpperCase() +"-"+config.General.DeployHash.toUpperCase()); + console.log("๐ŸŒŽ CDK deployment region:","\x1b[33m","\n "+deploymentRegion,"\x1b[0m \n"); (async () => { - let exitCode = 0; - const StackName = config.General.Prefix.toUpperCase() + "-WAF-" + config.WebAcl.Name.toUpperCase() +"-"+config.General.Stage.toUpperCase() +"-"+config.General.DeployHash.toUpperCase() - if(Temp_Hash === config.General.DeployHash){ - const policies = await ListPolicies(); - if(process.env.SKIP_QUOTA_CHECK == "true"){ - console.log("โ—๏ธ SKIPPING Quota Check for Quota: L-0B28E140") - } - else{ - const quota_policies = await CheckQuota("L-0B28E140"); - if(quota_policies <= policies){ - console.log("\n๐Ÿšจ You are about to exceed the limit for Policies per region.\n Region Quota: " +quota_policies + "\n Deployed Policies: " + policies + "\n ๏น— Stopping deployment ๏น—") - exitCode = 1; + const isNewStack = (config.General.DeployHash === ""); + const runtimeProperties = initRuntimeProperties(); + if(isNewStack){ + console.log("โ„น First Deployment of this WAF."); + const tempHash = Date.now().toString(36); + config.General.DeployHash = tempHash; + console.log("#๏ธโƒฃ Generated Deployment Hash for this WAF: "+ config.General.DeployHash); + if (process.env.SKIP_QUOTA_CHECK === "true") { + console.log("โ—๏ธ SKIPPING Quota Check for Policies."); + } else { + const policyQuotaReached = await isPolicyQuotaReached(deploymentRegion); + if (policyQuotaReached) { + console.error("\u001B[31m","๐Ÿšจ Exit process due Quota Check for Policies ๐Ÿšจ \n\n","\x1b[0m" + "\n\n"); + process.exit(1); } } - console.log("โ„น First Deployment of this WAF.") - }else{ - await GetOutputsFromStack(StackName, config); } - let count = 0 - let pre_calculate_capacity_sum = 0 - if(config.WebAcl.PreProcess.CustomRules === undefined){ - console.log("\n โญ Skip Rule Capacity Calculation for PreProcess Custom Rules.")} else{ - while (count < config.WebAcl.PreProcess.CustomRules.length) { - if("Captcha" in config.WebAcl.PreProcess.CustomRules[count].Action){ - const rule_calculated_capacity_json = []; - const temp_template = template; - temp_template.Statement = config.WebAcl.PreProcess.CustomRules[count].Statement; - temp_template.Action = config.WebAcl.PreProcess.CustomRules[count].Action; - temp_template.CaptchaConfig = config.WebAcl.PreProcess.CustomRules[count].CaptchaConfig; - rule_calculated_capacity_json.push(temp_template); - const capacity = await CheckCapacity(config.WebAcl.Scope, rule_calculated_capacity_json); - runtimeprops.PreProcessRuleCapacities.push(capacity); - } - else{ - const rule_calculated_capacity_json = []; - const temp_template = template; - temp_template.Statement = config.WebAcl.PreProcess.CustomRules[count].Statement; - temp_template.Action = config.WebAcl.PreProcess.CustomRules[count].Action; - delete temp_template.CaptchaConfig - rule_calculated_capacity_json.push(temp_template); - const capacity = await CheckCapacity(config.WebAcl.Scope, rule_calculated_capacity_json); - runtimeprops.PreProcessRuleCapacities.push(capacity); - } - count++ - } - pre_calculate_capacity_sum = runtimeprops.PreProcessRuleCapacities.reduce(function (a, b) { - return a + b; - }, 0); + await setOutputsFromStack(deploymentRegion, runtimeProperties, config); + console.log("#๏ธโƒฃ Deployment Hash for this WAF: "+ config.General.DeployHash); } - count = 0 - let post_calculate_capacity_sum = 0 - if(config.WebAcl.PostProcess.CustomRules === undefined){ - console.log("\n โญ Skip Rule Capacity Calculation for PostProcess Custom Rules.") - } - else{ - while (count < config.WebAcl.PostProcess.CustomRules.length) { - const rule_calculated_capacity_json = []; - const temp_template = template; - if("Captcha" in config.WebAcl.PostProcess.CustomRules[count].Action){ - temp_template.CaptchaConfig = config.WebAcl.PostProcess.CustomRules[count].CaptchaConfig; - } - else{ - delete temp_template.CaptchaConfig - } - if(config.WebAcl.PostProcess.CustomRules[count].RuleLabels){ - temp_template.RuleLabels = config.WebAcl.PostProcess.CustomRules[count].RuleLabels; - } - else{ - delete temp_template.RuleLabels - } - temp_template.Statement = config.WebAcl.PostProcess.CustomRules[count].Statement; - temp_template.Action = config.WebAcl.PostProcess.CustomRules[count].Action; - rule_calculated_capacity_json.push(temp_template); - const capacity = await CheckCapacity(config.WebAcl.Scope, rule_calculated_capacity_json); - runtimeprops.PostProcessRuleCapacities.push(capacity); - count++ - } - post_calculate_capacity_sum = runtimeprops.PostProcessRuleCapacities.reduce(function (a, b) { - return a + b; - }, 0); - } - let managedrule; - let managedrulecapacity = 0; - console.log("\n๐Ÿ‘€ Get ManagedRule Capacity:\n") - if(config.WebAcl.PreProcess.ManagedRuleGroups === undefined){ - console.log("\n โ„น๏ธ No ManagedRuleGroups defined in PreProcess.") - } - else{ - console.log(" ๐Ÿฅ‡ PreProcess: ") - for(managedrule of config.WebAcl.PreProcess.ManagedRuleGroups){ - const capacity = await GetManagedRuleCapacity(managedrule.Vendor,managedrule.Name,config.WebAcl.Scope,managedrule.Version) - managedrule.Capacity = capacity - console.log(" โž• Capacity for " + managedrule.Name + " is [" + managedrule.Capacity + "]") - managedrulecapacity = managedrulecapacity + capacity - } - } - if(config.WebAcl.PostProcess.ManagedRuleGroups === undefined){ - console.log("\n โ„น๏ธ No ManagedRuleGroups defined in PostProcess.") - } - else{ - console.log("\n ๐Ÿฅˆ PostProcess: ") - for(managedrule of config.WebAcl.PostProcess.ManagedRuleGroups){ - const capacity = await GetManagedRuleCapacity(managedrule.Vendor,managedrule.Name,config.WebAcl.Scope,managedrule.Version) - managedrule.Capacity = capacity - console.log(" โž• Capacity for " + managedrule.Name + " is [" + managedrule.Capacity + "]") - managedrulecapacity = managedrulecapacity + capacity - } - } - runtimeprops.PreProcessCapacity = pre_calculate_capacity_sum - runtimeprops.PostProcessCapacity = post_calculate_capacity_sum - const custom_capacity = runtimeprops.PreProcessCapacity + runtimeprops.PostProcessCapacity - const total_wcu = runtimeprops.PreProcessCapacity + runtimeprops.PostProcessCapacity + managedrulecapacity - const quote_wcu = await CheckQuota("L-D86ED2F3"); - if (total_wcu <= Number(quote_wcu)) { - console.log("\n๐Ÿ”Ž Capacity Check result: ๐ŸŸข \n") - console.log(" ๐Ÿ’ก Account WAF-WCU Quota: " +Number(quote_wcu).toString()) - console.log(" ๐Ÿงฎ Calculated Custom Rule Capacity is: [" + custom_capacity + "] (๐Ÿฅ‡[" + runtimeprops.PreProcessCapacity + "] + ๐Ÿฅˆ[" + runtimeprops.PostProcessCapacity + "]) \n โž• ManagedRulesCapacity: ["+ managedrulecapacity +"] \n ๏ผ Total Waf Capacity: " + total_wcu.toString() + "\n") - } - else { - console.log("\n๐Ÿ”Ž Capacity Check result: ๐Ÿ”ด \n ๏น— Stopping deployment ๏น—\n") - console.log(" ๐Ÿ’ก Account WAF-WCU Quota: " +Number(quote_wcu).toString()) - console.log(" ๐Ÿงฎ Calculated Custom Rule Capacity is: [" + custom_capacity + "] \n โž• ManagedRulesCapacity: ["+ managedrulecapacity +"] \n ๏ผ Total Waf Capacity: " + total_wcu.toString() + "\n") - exitCode = 1; - } - if(exitCode == 1){ - process.exitCode = 1; + console.log("๐Ÿ”ฅ Deploy FMS Policy: " + config.General.Prefix.toUpperCase() + "-" + config.WebAcl.Name.toUpperCase()+ "-" + config.General.Stage + "-" + config.General.DeployHash + "\n โฆ‚ Type: " +config.WebAcl.Type + "\n๐Ÿ“š Stackname: " + config.General.Prefix.toUpperCase() + "-WAF-" + config.WebAcl.Name.toUpperCase() +"-"+config.General.Stage.toUpperCase() +"-"+config.General.DeployHash.toUpperCase()); + const wcuQuotaReached = await isWcuQuotaReached(deploymentRegion, runtimeProperties, config); + if(wcuQuotaReached) { + console.error("\u001B[31m","๐Ÿšจ Exit process due Quota Check for WCU ๐Ÿšจ \n\n","\x1b[0m" + "\n\n"); + process.exit(1); } + const app = new cdk.App(); new PlattformWafv2CdkAutomationStack(app, config.General.Prefix.toUpperCase() + "-WAF-" + config.WebAcl.Name.toUpperCase() +"-"+config.General.Stage.toUpperCase() +"-"+config.General.DeployHash.toUpperCase(), { - config, runtimeprops, + config, runtimeProperties: runtimeProperties, env: { - region: deploymentregion, + region: deploymentRegion, account: process.env.CDK_DEFAULT_ACCOUNT, }, }); - //app.synth() })(); - // } - }else { + } else { console.log(` โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ• - โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• - โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•šโ–ˆโ–ˆโ•”โ• - โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ - โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• + โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• + โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•šโ–ˆโ–ˆโ•”โ• + โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ + โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• `); - console.log("\n๐Ÿท Version: ","\x1b[4m",afwfver,"\x1b[0m") - console.log("\n ๐Ÿงช Validation of your ConfigFile: \n ๐Ÿ“‚ " + configFile + "\n\n") + console.log("\n๐Ÿท Version: ","\x1b[4m",FIREWALL_FACTORY_VERSION,"\x1b[0m"); + console.log("\n ๐Ÿงช Validation of your ConfigFile: \n ๐Ÿ“‚ " + configFile + "\n\n"); console.error("\u001B[31m","๐Ÿšจ Invalid Configuration File ๐Ÿšจ \n\n","\x1b[0m" + JSON.stringify(validate.errors, null, 2)+ "\n\n"); - process.exitCode = 1; + process.exit(1); } } else { console.log("File", configFile, "not found. - NO CDK ERROR"); } -function elseif() { - throw new Error("Function not implemented."); -} diff --git a/lib/plattform-wafv2-cdk-automation-stack.ts b/lib/plattform-wafv2-cdk-automation-stack.ts index d272fc7e..3f598c0e 100644 --- a/lib/plattform-wafv2-cdk-automation-stack.ts +++ b/lib/plattform-wafv2-cdk-automation-stack.ts @@ -1,42 +1,43 @@ import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; -import {aws_wafv2 as wafv2} from "aws-cdk-lib"; -import {aws_fms as fms} from "aws-cdk-lib"; -import {aws_kinesisfirehose as firehouse} from "aws-cdk-lib"; -import {aws_iam as iam} from "aws-cdk-lib"; -import {aws_logs as logs} from "aws-cdk-lib"; +import { aws_wafv2 as wafv2 } from "aws-cdk-lib"; +import { aws_fms as fms } from "aws-cdk-lib"; +import { aws_kinesisfirehose as firehouse } from "aws-cdk-lib"; +import { aws_iam as iam } from "aws-cdk-lib"; +import { aws_logs as logs } from "aws-cdk-lib"; import { Config } from "./types/config"; -import { Runtimeprops } from "./types/runtimeprops"; +import { RuntimeProperties } from "./types/runtimeprops"; import { promises as fsp } from "fs"; -import { toCamel } from "./tools/camel-case" +import { toAwsCamel } from "./tools/helpers"; export interface ConfigStackProps extends cdk.StackProps { readonly config: Config; - runtimeprops: Runtimeprops; + runtimeProperties: RuntimeProperties; } - export class PlattformWafv2CdkAutomationStack extends cdk.Stack { constructor(scope: Construct, id: string, props: ConfigStackProps) { super(scope, id, props); const account_id = cdk.Aws.ACCOUNT_ID; const region = cdk.Aws.REGION; - if(props.runtimeprops.PreProcessDeployedRuleGroupCapacities === undefined){ - console.log("โš™๏ธ Initialize PreProcess lists for Update mechanism.") - props.runtimeprops.PreProcessDeployedRuleGroupCapacities = [] - props.runtimeprops.PreProcessDeployedRuleGroupNames = [] - props.runtimeprops.PreProcessDeployedRuleGroupIdentifier = []} - if(props.runtimeprops.PostProcessDeployedRuleGroupCapacities === undefined){ - console.log("โš™๏ธ Initialize PostProcess lists for Update mechanism.") - props.runtimeprops.PostProcessDeployedRuleGroupCapacities = [] - props.runtimeprops.PostProcessDeployedRuleGroupNames = [] - props.runtimeprops.PostProcessDeployedRuleGroupIdentifier = []} - const CfnRole = new iam.CfnRole(this, "KinesisS3DeliveryRole",{ - assumeRolePolicyDocument: {"Version":"2012-10-17","Statement":[{"Sid":"","Effect":"Allow","Principal":{"Service":"firehose.amazonaws.com"},"Action":"sts:AssumeRole"}]} - }) - - const CfnLogGroup = new logs.CfnLogGroup(this, "KinesisErrorLogging",{ - retentionInDays: 90}) + + const CfnRole = new iam.CfnRole(this, "KinesisS3DeliveryRole", { + assumeRolePolicyDocument: { + Version: "2012-10-17", + Statement: [ + { + Sid: "", + Effect: "Allow", + Principal: { Service: "firehose.amazonaws.com" }, + Action: "sts:AssumeRole", + }, + ], + }, + }); + + const CfnLogGroup = new logs.CfnLogGroup(this, "KinesisErrorLogging", { + retentionInDays: 90, + }); const policy = { Version: "2012-10-17", @@ -50,361 +51,599 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject", - "s3:PutObjectAcl" + "s3:PutObjectAcl", ], Resource: [ - "arn:aws:s3:::"+props.config.General.S3LoggingBucketName, - "arn:aws:s3:::"+props.config.General.S3LoggingBucketName +"/*" - ] + "arn:aws:s3:::" + props.config.General.S3LoggingBucketName, + "arn:aws:s3:::" + props.config.General.S3LoggingBucketName + "/*", + ], }, { Effect: "Allow", - Action: [ - "logs:PutLogEvents" - ], - Resource: [ - CfnLogGroup.attrArn - ] + Action: ["logs:PutLogEvents"], + Resource: [CfnLogGroup.attrArn], }, { Effect: "Allow", - Action: [ - "kms:Decrypt", - "kms:GenerateDataKey" - ], - Resource: [ - props.config.General.FireHoseKeyArn - ] - } - ] - } + Action: ["kms:Decrypt", "kms:GenerateDataKey"], + Resource: [props.config.General.FireHoseKeyArn], + }, + ], + }; - new iam.CfnPolicy(this, "KinesisS3DeliveryPolicy",{ + new iam.CfnPolicy(this, "KinesisS3DeliveryPolicy", { policyDocument: policy, policyName: "firehose_delivery_policy", - roles: [CfnRole.ref] - }) + roles: [CfnRole.ref], + }); - new firehouse.CfnDeliveryStream(this, "S3DeliveryStream",{ - deliveryStreamName: "aws-waf-logs-"+props.config.General.Prefix+"-kinesis-wafv2log-"+props.config.WebAcl.Name+props.config.General.Stage+props.config.General.DeployHash, + new firehouse.CfnDeliveryStream(this, "S3DeliveryStream", { + deliveryStreamName: + "aws-waf-logs-" + + props.config.General.Prefix + + "-kinesis-wafv2log-" + + props.config.WebAcl.Name + + props.config.General.Stage + + props.config.General.DeployHash, extendedS3DestinationConfiguration: { - bucketArn:"arn:aws:s3:::"+props.config.General.S3LoggingBucketName, - encryptionConfiguration:{kmsEncryptionConfig:{awskmsKeyArn:props.config.General.FireHoseKeyArn}}, + bucketArn: "arn:aws:s3:::" + props.config.General.S3LoggingBucketName, + encryptionConfiguration: { + kmsEncryptionConfig: { + awskmsKeyArn: props.config.General.FireHoseKeyArn, + }, + }, roleArn: CfnRole.attrArn, - bufferingHints: {sizeInMBs:50, intervalInSeconds:60}, + bufferingHints: { sizeInMBs: 50, intervalInSeconds: 60 }, compressionFormat: "UNCOMPRESSED", - prefix: "AWSLogs/"+ account_id +"/FirewallManager/"+region+"/", - errorOutputPrefix: "AWSLogs/"+ account_id +"/FirewallManager/"+region+"/Errors" + prefix: "AWSLogs/" + account_id + "/FirewallManager/" + region + "/", + errorOutputPrefix: + "AWSLogs/" + account_id + "/FirewallManager/" + region + "/Errors", }, + }); - }) - - if(props.config.WebAcl.PreProcess.CustomRules === undefined && props.config.WebAcl.PostProcess.CustomRules === undefined) - { - console.log("Creating DEFAULT Policy.") - const novalue = null + if ( + !props.config.WebAcl.PreProcess.CustomRules && + !props.config.WebAcl.PostProcess.CustomRules + ) { + console.log("Creating DEFAULT Policy."); + const novalue = null; let mangedrule; let ExcludeRules; let OverrideAction; - const preProcessRuleGroups = [] - const postProcessRuleGroups = [] - if(props.config.WebAcl.PreProcess.ManagedRuleGroups === undefined){ - console.log("\nโ„น๏ธ No ManagedRuleGroups defined in PreProcess.") - } - else{ - for(mangedrule of props.config.WebAcl.PreProcess.ManagedRuleGroups){ - if(mangedrule.ExcludeRules){ - ExcludeRules = toCamel(mangedrule.ExcludeRules) - OverrideAction = mangedrule.OverrideAction + const preProcessRuleGroups = []; + const postProcessRuleGroups = []; + if (!props.config.WebAcl.PreProcess.ManagedRuleGroups) { + console.log("\nโ„น๏ธ No ManagedRuleGroups defined in PreProcess."); + } else { + for (mangedrule of props.config.WebAcl.PreProcess.ManagedRuleGroups) { + if (mangedrule.ExcludeRules) { + ExcludeRules = toAwsCamel(mangedrule.ExcludeRules); + OverrideAction = mangedrule.OverrideAction; + } else { + ExcludeRules = []; + OverrideAction = { type: "NONE" }; } - 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", + }); } - 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"});} } } - if(props.config.WebAcl.PostProcess.ManagedRuleGroups === undefined){ - console.log("โ„น๏ธ No ManagedRuleGroups defined in PostProcess.") - } - else{ - for(mangedrule of props.config.WebAcl.PostProcess.ManagedRuleGroups){ - if(mangedrule.ExcludeRules){ - ExcludeRules = toCamel(mangedrule.ExcludeRules) - OverrideAction = mangedrule.OverrideAction + if (!props.config.WebAcl.PostProcess.ManagedRuleGroups) { + console.log("โ„น๏ธ No ManagedRuleGroups defined in PostProcess."); + } else { + for (mangedrule of props.config.WebAcl.PostProcess.ManagedRuleGroups) { + if (mangedrule.ExcludeRules) { + ExcludeRules = toAwsCamel(mangedrule.ExcludeRules); + OverrideAction = mangedrule.OverrideAction; + } else { + ExcludeRules = []; + OverrideAction = { type: "NONE" }; } - else{ - ExcludeRules = [] - OverrideAction = { "type": "NONE" } + if (mangedrule.Version === "") { + postProcessRuleGroups.push({ + managedRuleGroupIdentifier: { + vendorName: mangedrule.Vendor, + managedRuleGroupName: mangedrule.Name, + version: novalue, + }, + overrideAction: OverrideAction, + ruleGroupArn: novalue, + excludeRules: ExcludeRules, + ruleGroupType: "ManagedRuleGroup", + }); + } else { + postProcessRuleGroups.push({ + managedRuleGroupIdentifier: { + vendorName: mangedrule.Vendor, + managedRuleGroupName: mangedrule.Name, + version: mangedrule.Version, + }, + overrideAction: OverrideAction, + ruleGroupArn: novalue, + excludeRules: ExcludeRules, + ruleGroupType: "ManagedRuleGroup", + }); } - if(mangedrule.Version === ""){ - postProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor, - "managedRuleGroupName":mangedrule.Name,"version": novalue},"overrideAction": OverrideAction, - "ruleGroupArn": novalue,"excludeRules": ExcludeRules,"ruleGroupType": "ManagedRuleGroup"});} - else{ - postProcessRuleGroups.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": preProcessRuleGroups, - "postProcessRuleGroups": postProcessRuleGroups, - "overrideCustomerWebACLAssociation":true, - "loggingConfiguration": { - "logDestinationConfigs":["${S3DeliveryStream.Arn}"] - } - } + 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, - 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))} + 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) + ), + }, }); - - } - else{ - const preProcessRuleGroups = [] - const postProcessRuleGroups = [] - if(props.config.WebAcl.PreProcess.CustomRules === undefined){ - console.log("\nโ„น๏ธ No Custom Rules defined in PreProcess.") - } - else{ - console.log("\u001b[1m","\n๐Ÿฅ‡ Custom Rules PreProcess: ","\x1b[0m\n") - if (props.runtimeprops.PreProcessCapacity < 1000){ + } else { + const preProcessRuleGroups = []; + const postProcessRuleGroups = []; + if (!props.config.WebAcl.PreProcess.CustomRules) { + console.log("\nโ„น๏ธ No Custom Rules defined in PreProcess."); + } else { + console.log( + "\u001b[1m", + "\n๐Ÿฅ‡ Custom Rules PreProcess: ", + "\x1b[0m\n" + ); + if (props.runtimeProperties.PreProcessCapacity < 1000) { const rules = []; - let count = 1 - for(const statement of props.config.WebAcl.PreProcess.CustomRules){ - let rulename = "" - if(statement.Name !== undefined){ - rulename = statement.Name + "-pre-" + props.config.General.DeployHash - } - else{ - rulename = props.config.WebAcl.Name + "-pre-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash + let count = 1; + for (const statement of props.config.WebAcl.PreProcess.CustomRules) { + let rulename = ""; + if (statement.Name !== undefined) { + rulename = + statement.Name + "-pre-" + props.config.General.DeployHash; + } else { + rulename = + props.config.WebAcl.Name + + "-pre-" + + props.config.General.Stage + + "-" + + count.toString() + + "-" + + props.config.General.DeployHash; } - let CfnRuleProperty - if("Captcha" in statement.Action){ + let CfnRuleProperty; + if ("Captcha" in statement.Action) { CfnRuleProperty = { name: rulename, priority: count, - action: toCamel(statement.Action), - statement: toCamel(statement.Statement), + action: toAwsCamel(statement.Action), + statement: toAwsCamel(statement.Statement), visibilityConfig: { - sampledRequestsEnabled: statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled, + sampledRequestsEnabled: + statement.VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: + statement.VisibilityConfig.CloudWatchMetricsEnabled, metricName: rulename + "-metric", }, - captchaConfig: toCamel(statement.CaptchaConfig), - ruleLabels: toCamel(statement.RuleLabels) - } - } - else{ + captchaConfig: toAwsCamel(statement.CaptchaConfig), + ruleLabels: toAwsCamel(statement.RuleLabels), + }; + } else { CfnRuleProperty = { name: rulename, priority: count, - action: toCamel(statement.Action), - statement: toCamel(statement.Statement), + action: toAwsCamel(statement.Action), + statement: toAwsCamel(statement.Statement), visibilityConfig: { - sampledRequestsEnabled: statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled, + sampledRequestsEnabled: + statement.VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: + statement.VisibilityConfig.CloudWatchMetricsEnabled, metricName: rulename + "-metric", }, - ruleLabels: toCamel(statement.RuleLabels) + ruleLabels: toAwsCamel(statement.RuleLabels), }; } - let CfnRuleProperties: wafv2.CfnRuleGroup.RuleProperty - if(statement.RuleLabels){ - CfnRuleProperties = CfnRuleProperty - } - else{ - const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty - CfnRuleProperties = CfnRulePropertii + let CfnRuleProperties: wafv2.CfnRuleGroup.RuleProperty; + if (statement.RuleLabels) { + CfnRuleProperties = CfnRuleProperty; + } else { + const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty; + CfnRuleProperties = CfnRulePropertii; } - rules.push(CfnRuleProperties) - count +=1 + rules.push(CfnRuleProperties); + count += 1; } - let name = props.config.WebAcl.Name + "-pre-" + props.config.General.Stage + "-" +props.config.General.DeployHash - let rulegroupidentifier = "PreRuleGroup" - if(typeof props.runtimeprops.PreProcessDeployedRuleGroupCapacities[0] !== "undefined"){ - if(props.runtimeprops.PreProcessDeployedRuleGroupCapacities[0] !== props.runtimeprops.PreProcessCapacity){ - console.log("โญ•๏ธ Deploy new RuleGroup because the Capacity has changed!") - console.log("\n ๐ŸŸฅ Old Capacity: ["+ props.runtimeprops.PreProcessDeployedRuleGroupCapacities[0] + "]\n ๐ŸŸฉ New Capacity: [" + props.runtimeprops.PreProcessCapacity+"]") - if(props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[0] === "RuleGroup"){ - rulegroupidentifier ="preRG" + let name = + props.config.WebAcl.Name + + "-pre-" + + props.config.General.Stage + + "-" + + props.config.General.DeployHash; + let rulegroupidentifier = "PreRuleGroup"; + if ( + typeof props.runtimeProperties + .PreProcessDeployedRuleGroupCapacities[0] !== "undefined" + ) { + if ( + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[0] !== + props.runtimeProperties.PreProcessCapacity + ) { + console.log( + "โญ•๏ธ Deploy new RuleGroup because the Capacity has changed!" + ); + console.log( + "\n ๐ŸŸฅ Old Capacity: [" + + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[0] + + "]\n ๐ŸŸฉ New Capacity: [" + + props.runtimeProperties.PreProcessCapacity + + "]" + ); + if ( + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[0] === + "RuleGroup" + ) { + rulegroupidentifier = "preRG"; } - if(props.runtimeprops.PreProcessDeployedRuleGroupNames[0] === props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" +props.config.General.DeployHash){ - name = props.config.General.Prefix.toUpperCase() + "-G" + props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" +props.config.General.DeployHash + if ( + props.runtimeProperties.PreProcessDeployedRuleGroupNames[0] === + props.config.WebAcl.Name + + "-" + + props.config.General.Stage + + "-" + + props.config.General.DeployHash + ) { + name = + props.config.General.Prefix.toUpperCase() + + "-G" + + props.config.WebAcl.Name + + "-" + + props.config.General.Stage + + "-" + + props.config.General.DeployHash; } - console.log(" ๐Ÿ’ฌ New Name: "+ name) - console.log(" ๐Ÿ“‡ New Identifier: "+ rulegroupidentifier) + console.log(" ๐Ÿ’ฌ New Name: " + name); + console.log(" ๐Ÿ“‡ New Identifier: " + rulegroupidentifier); } } - new wafv2.CfnRuleGroup(this,rulegroupidentifier, { - capacity: props.runtimeprops.PreProcessCapacity, + new wafv2.CfnRuleGroup(this, rulegroupidentifier, { + capacity: props.runtimeProperties.PreProcessCapacity, scope: props.config.WebAcl.Scope, rules: rules, name: name, visibilityConfig: { sampledRequestsEnabled: false, cloudWatchMetricsEnabled: false, - metricName: props.config.General.Prefix.toUpperCase() + "-" + props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" +props.config.General.DeployHash, - } + metricName: + props.config.General.Prefix.toUpperCase() + + "-" + + props.config.WebAcl.Name + + "-" + + props.config.General.Stage + + "-" + + props.config.General.DeployHash, + }, }); - preProcessRuleGroups.push({"ruleGroupType":"RuleGroup","ruleGroupArn":"${"+ rulegroupidentifier +".Arn}","overrideAction":{"type":"NONE"}}); - console.log(" โžก๏ธ Creating " + rulegroupidentifier + " with calculated capacity: [" + props.runtimeprops.PreProcessCapacity +"]") - props.runtimeprops.PreProcessDeployedRuleGroupCapacities.splice(0) - props.runtimeprops.PreProcessDeployedRuleGroupIdentifier.splice(0) - props.runtimeprops.PreProcessDeployedRuleGroupNames.splice(0) - - props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[0] = rulegroupidentifier - props.runtimeprops.PreProcessDeployedRuleGroupNames[0] = name - props.runtimeprops.PreProcessDeployedRuleGroupCapacities[0] = props.runtimeprops.PreProcessCapacity + preProcessRuleGroups.push({ + ruleGroupType: "RuleGroup", + ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", + overrideAction: { type: "NONE" }, + }); + console.log( + " โžก๏ธ Creating " + + rulegroupidentifier + + " with calculated capacity: [" + + props.runtimeProperties.PreProcessCapacity + + "]" + ); + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.splice(0); + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.splice(0); + props.runtimeProperties.PreProcessDeployedRuleGroupNames.splice(0); + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[0] = + rulegroupidentifier; + props.runtimeProperties.PreProcessDeployedRuleGroupNames[0] = name; + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[0] = + props.runtimeProperties.PreProcessCapacity; new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupNames", { - value: props.runtimeprops.PreProcessDeployedRuleGroupNames.toString(), + value: + props.runtimeProperties.PreProcessDeployedRuleGroupNames.toString(), description: "PreProcessDeployedRuleGroupNames", - exportName: "PreProcessDeployedRuleGroupNames"+props.config.General.DeployHash, + exportName: + "PreProcessDeployedRuleGroupNames" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupCapacities", { - value: props.runtimeprops.PreProcessDeployedRuleGroupCapacities.toString(), + value: + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.toString(), description: "PreProcessDeployedRuleGroupCapacities", - exportName: "PreProcessDeployedRuleGroupCapacities"+props.config.General.DeployHash, + exportName: + "PreProcessDeployedRuleGroupCapacities" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupIdentifier", { - value: props.runtimeprops.PreProcessDeployedRuleGroupIdentifier.toString(), + value: + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.toString(), description: "PreProcessDeployedRuleGroupIdentifier", - exportName: "PreProcessDeployedRuleGroupIdentifier"+props.config.General.DeployHash, + exportName: + "PreProcessDeployedRuleGroupIdentifier" + + 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) + } else { + const threshold = 1000; + const rulesets: any[] = []; + const indexes: number[] = []; + const rulegroupcapacities = []; + while ( + indexes.length < props.runtimeProperties.PreProcessRuleCapacities.length + ) { + let tracker = 0; + const ruleset: any[] = []; + props.runtimeProperties.PreProcessRuleCapacities.map((v, i) => { + 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`); - 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( + ` ๐Ÿ–– Split Rules into ${rulesets.length.toString()} RuleGroups: \n` + ); + let count = 0; + let rulegroupidentifier = ""; + let name = ""; + while (count < rulesets.length) { + if ( + typeof props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[ + count + ] !== "undefined" + ) { + if ( + rulegroupcapacities[count] === + props.runtimeProperties.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.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[ + count + ] + + " !" + ); + console.log( + "\n ๐ŸŸฅ Old Capacity: [" + + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[ + count + ] + + "]\n ๐ŸŸฉ New Capacity: [" + + rulegroupcapacities[count] + + "]" + ); + if ( + typeof props.runtimeProperties + .PreProcessDeployedRuleGroupCapacities[count] !== + "undefined" + ) { + if ( + props.runtimeProperties.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) + console.log(" ๐Ÿ’ฌ New Name: " + name); } - if(typeof props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[count] !== undefined){ - if(props.runtimeprops.PreProcessDeployedRuleGroupIdentifier[count] === "R"+count.toString()){ - rulegroupidentifier = "preG"+count.toString() - } - else{ - rulegroupidentifier = "preR"+count.toString() + if ( + typeof props.runtimeProperties + .PreProcessDeployedRuleGroupIdentifier[count] !== undefined + ) { + if ( + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[ + count + ] === + "R" + count.toString() + ) { + rulegroupidentifier = "preG" + count.toString(); + } else { + rulegroupidentifier = "preR" + count.toString(); } - console.log(" ๐Ÿ“‡ New Identifier: "+ rulegroupidentifier + "\n") + console.log( + " ๐Ÿ“‡ New Identifier: " + rulegroupidentifier + "\n" + ); } } - }else{ - rulegroupidentifier = "preR"+count.toString() - name = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash + } 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 + 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; } - 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){ + 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), + action: toAwsCamel( + props.config.WebAcl.PreProcess.CustomRules[statementindex] + .Action + ), + statement: toAwsCamel( + 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, + 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{ + captchaConfig: toAwsCamel( + props.config.WebAcl.PreProcess.CustomRules[statementindex] + .CaptchaConfig + ), + ruleLabels: toAwsCamel( + props.config.WebAcl.PreProcess.CustomRules[statementindex] + .RuleLabels + ), + }; + } else { CfnRuleProperty = { name: rulename, priority: rulegroupcounter, - action: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].Action), - statement: toCamel(props.config.WebAcl.PreProcess.CustomRules[statementindex].Statement), + action: toAwsCamel( + props.config.WebAcl.PreProcess.CustomRules[statementindex] + .Action + ), + statement: toAwsCamel( + 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, + 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) - } - } - let CfnRuleProperti: wafv2.CfnRuleGroup.RuleProperty - if(props.config.WebAcl.PreProcess.CustomRules[statementindex].RuleLabels){ - CfnRuleProperti = CfnRuleProperty + ruleLabels: toAwsCamel( + props.config.WebAcl.PreProcess.CustomRules[statementindex] + .RuleLabels + ), + }; } - else{ - const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty - CfnRuleProperti = CfnRulePropertii + 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++ + CfnRuleProperties.push(CfnRuleProperti); + rulegroupcounter++; } - new wafv2.CfnRuleGroup(this,rulegroupidentifier, { + new wafv2.CfnRuleGroup(this, rulegroupidentifier, { capacity: rulegroupcapacities[count], scope: props.config.WebAcl.Scope, rules: CfnRuleProperties, @@ -413,116 +652,188 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { 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++ + preProcessRuleGroups.push({ + ruleGroupType: "RuleGroup", + ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", + overrideAction: { type: "NONE" }, + }); + console.log( + " โžก๏ธ Creating " + + rulegroupidentifier + + " with calculated capacity: [" + + rulegroupcapacities[count].toString() + + "]" + ); + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[count] = + rulegroupcapacities[count]; + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[count] = + rulegroupidentifier; + props.runtimeProperties.PreProcessDeployedRuleGroupNames[count] = name; + count++; } - const lenght = rulesets.length - props.runtimeprops.PreProcessDeployedRuleGroupCapacities.splice(lenght) - props.runtimeprops.PreProcessDeployedRuleGroupIdentifier.splice(lenght) - props.runtimeprops.PreProcessDeployedRuleGroupNames.splice(lenght) + const lenght = rulesets.length; + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.splice( + lenght + ); + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.splice( + lenght + ); + props.runtimeProperties.PreProcessDeployedRuleGroupNames.splice(lenght); new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupNames", { - value: props.runtimeprops.PreProcessDeployedRuleGroupNames.toString(), + value: + props.runtimeProperties.PreProcessDeployedRuleGroupNames.toString(), description: "PreProcessDeployedRuleGroupNames", - exportName: "PreProcessDeployedRuleGroupNames"+props.config.General.DeployHash, + exportName: + "PreProcessDeployedRuleGroupNames" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupCapacities", { - value: props.runtimeprops.PreProcessDeployedRuleGroupCapacities.toString(), + value: + props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.toString(), description: "PreProcessDeployedRuleGroupCapacities", - exportName: "PreProcessDeployedRuleGroupCapacities"+props.config.General.DeployHash, + exportName: + "PreProcessDeployedRuleGroupCapacities" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupIdentifier", { - value: props.runtimeprops.PreProcessDeployedRuleGroupIdentifier.toString(), + value: + props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.toString(), description: "PreProcessDeployedRuleGroupIdentifier", - exportName: "PreProcessDeployedRuleGroupIdentifier"+props.config.General.DeployHash, + 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){ + if (!props.config.WebAcl.PostProcess.CustomRules) { + console.log("\nโ„น๏ธ No Custom Rules defined in PostProcess."); + } else { + console.log( + "\u001b[1m", + "\n๐Ÿฅˆ Custom Rules PostProcess:", + "\x1b[0m\n" + ); + if (props.runtimeProperties.PostProcessCapacity < 1000) { const rules = []; - let count = 1 + let count = 1; - for(const statement of props.config.WebAcl.PostProcess.CustomRules){ - let rulename = "" - if(statement.Name !== undefined){ - rulename = statement.Name + "-post-" + props.config.General.DeployHash + for (const statement of props.config.WebAcl.PostProcess.CustomRules) { + let rulename = ""; + if (statement.Name !== undefined) { + rulename = + statement.Name + "-post-" + props.config.General.DeployHash; + } else { + rulename = + props.config.WebAcl.Name + + "-" + + props.config.General.Stage + + "-post-" + + count.toString() + + "-" + + props.config.General.DeployHash; } - else{ - rulename = props.config.WebAcl.Name + "-" + props.config.General.Stage + "-post-" + count.toString() + "-" +props.config.General.DeployHash - } - let CfnRuleProperty - if("Captcha" in statement.Action){ + let CfnRuleProperty; + if ("Captcha" in statement.Action) { CfnRuleProperty = { name: rulename, priority: count, - action: toCamel(statement.Action), - statement: toCamel(statement.Statement), + action: toAwsCamel(statement.Action), + statement: toAwsCamel(statement.Statement), visibilityConfig: { - sampledRequestsEnabled: statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: statement.VisibilityConfig.CloudWatchMetricsEnabled, + sampledRequestsEnabled: + statement.VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: + statement.VisibilityConfig.CloudWatchMetricsEnabled, metricName: rulename + "-metric", }, - captchaConfig: toCamel(statement.CaptchaConfig), - ruleLabels: toCamel(statement.RuleLabels) - } - } - else{ + captchaConfig: toAwsCamel(statement.CaptchaConfig), + ruleLabels: toAwsCamel(statement.RuleLabels), + }; + } else { CfnRuleProperty = { name: rulename, priority: count, - action: toCamel(statement.Action), - statement: toCamel(statement.Statement), + action: toAwsCamel(statement.Action), + statement: toAwsCamel(statement.Statement), visibilityConfig: { - sampledRequestsEnabled: statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: statement.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 + ruleLabels: toAwsCamel(statement.RuleLabels), + }; } - else{ - const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty - CfnRuleProperti = CfnRulePropertii + let CfnRuleProperti: wafv2.CfnRuleGroup.RuleProperty; + if (statement.RuleLabels) { + CfnRuleProperti = CfnRuleProperty; + } else { + const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty; + CfnRuleProperti = CfnRulePropertii; } - rules.push(CfnRuleProperti) - count +=1 + rules.push(CfnRuleProperti); + count += 1; } - 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" + let name = + props.config.WebAcl.Name + + "-post-" + + props.config.General.Stage + + "-" + + props.config.General.DeployHash; + let rulegroupidentifier = "PostRuleGroup"; + if ( + typeof props.runtimeProperties + .PostProcessDeployedRuleGroupCapacities[0] !== "undefined" + ) { + if ( + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[0] !== + props.runtimeProperties.PostProcessCapacity + ) { + console.log( + "โญ•๏ธ Deploy new RuleGroup because the Capacity has changed!" + ); + console.log( + "\n ๐ŸŸฅ Old Capacity: [" + + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[0] + + "]\n ๐ŸŸฉ New Capacity: [" + + props.runtimeProperties.PostProcessCapacity + + "]" + ); + if ( + props.runtimeProperties.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 + if ( + props.runtimeProperties.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) + console.log(" ๐Ÿ’ฌ New Name: " + name); + console.log(" ๐Ÿ“‡ New Identifier: " + rulegroupidentifier); } } - new wafv2.CfnRuleGroup(this,rulegroupidentifier, { - capacity: props.runtimeprops.PostProcessCapacity, + new wafv2.CfnRuleGroup(this, rulegroupidentifier, { + capacity: props.runtimeProperties.PostProcessCapacity, scope: props.config.WebAcl.Scope, rules: rules, name: name, @@ -530,150 +841,294 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { sampledRequestsEnabled: false, cloudWatchMetricsEnabled: false, 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 + postProcessRuleGroups.push({ + ruleGroupType: "RuleGroup", + ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", + overrideAction: { type: "NONE" }, + }); + console.log( + " โžก๏ธ Creating " + + rulegroupidentifier + + " with calculated capacity: [" + + props.runtimeProperties.PostProcessCapacity + + "]" + ); + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.splice(0); + props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.splice(0); + props.runtimeProperties.PostProcessDeployedRuleGroupNames.splice(0); + props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[0] = + rulegroupidentifier; + props.runtimeProperties.PostProcessDeployedRuleGroupNames[0] = name; + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[0] = + props.runtimeProperties.PostProcessCapacity; new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupNames", { - value: props.runtimeprops.PostProcessDeployedRuleGroupNames.toString(), + value: + props.runtimeProperties.PostProcessDeployedRuleGroupNames.toString(), description: "PostProcessDeployedRuleGroupNames", - exportName: "PostProcessDeployedRuleGroupNames"+props.config.General.DeployHash, + exportName: + "PostProcessDeployedRuleGroupNames" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupCapacities", { - value: props.runtimeprops.PostProcessDeployedRuleGroupCapacities.toString(), + value: + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.toString(), description: "PostProcessDeployedRuleGroupCapacities", - exportName: "PostProcessDeployedRuleGroupCapacities"+props.config.General.DeployHash, + exportName: + "PostProcessDeployedRuleGroupCapacities" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupIdentifier", { - value: props.runtimeprops.PostProcessDeployedRuleGroupIdentifier.toString(), + value: + props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.toString(), description: "PostProcessDeployedRuleGroupIdentifier", - exportName: "PostProcessDeployedRuleGroupIdentifier"+props.config.General.DeployHash, + exportName: + "PostProcessDeployedRuleGroupIdentifier" + + 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) + } else { + const threshold = 1000; + const rulesets: any[] = []; + const indexes: number[] = []; + const rulegroupcapacities = []; + while ( + indexes.length < props.runtimeProperties.PostProcessRuleCapacities.length + ) { + let tracker = 0; + const ruleset: any[] = []; + props.runtimeProperties.PostProcessRuleCapacities.map((v, i) => { + 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`); - 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( + ` ๐Ÿ–– Split Rules into ${rulesets.length.toString()} RuleGroups:\n` + ); + let count = 0; + let rulegroupidentifier = ""; + let name = ""; + while (count < rulesets.length) { + if ( + typeof props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[ + count + ] !== "undefined" + ) { + if ( + rulegroupcapacities[count] === + props.runtimeProperties.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.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[ + count + ] + + " !" + ); + console.log( + "\n ๐ŸŸฅ Old Capacity: [" + + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[ + count + ] + + "]\n ๐ŸŸฉ New Capacity: [" + + rulegroupcapacities[count] + + "]" + ); + if ( + typeof props.runtimeProperties + .PostProcessDeployedRuleGroupCapacities[count] !== + "undefined" + ) { + if ( + props.runtimeProperties.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) + 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() + if ( + typeof props.runtimeProperties + .PostProcessDeployedRuleGroupIdentifier[count] !== undefined + ) { + if ( + props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[ + count + ] === + "R" + count.toString() + ) { + rulegroupidentifier = "postG" + count.toString(); + } else { + rulegroupidentifier = "postR" + count.toString(); } - console.log(" ๐Ÿ“‡ New Identifier: "+ rulegroupidentifier + "\n") + 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 + } 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 + 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; } - 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){ + 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), + action: toAwsCamel( + props.config.WebAcl.PostProcess.CustomRules[statementindex] + .Action + ), + statement: toAwsCamel( + 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, + 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{ + captchaConfig: toAwsCamel( + props.config.WebAcl.PostProcess.CustomRules[statementindex] + .CaptchaConfig + ), + ruleLabels: toAwsCamel( + 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), + action: toAwsCamel( + props.config.WebAcl.PostProcess.CustomRules[statementindex] + .Action + ), + statement: toAwsCamel( + 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, + 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 + ruleLabels: toAwsCamel( + props.config.WebAcl.PostProcess.CustomRules[statementindex] + .RuleLabels + ), + }; } - else{ - const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty - CfnRuleProperti = CfnRulePropertii + 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++ + CfnRuleProperties.push(CfnRuleProperti); + rulegroupcounter++; } - new wafv2.CfnRuleGroup(this,rulegroupidentifier, { + new wafv2.CfnRuleGroup(this, rulegroupidentifier, { capacity: rulegroupcapacities[count], scope: props.config.WebAcl.Scope, rules: CfnRuleProperties, @@ -681,166 +1136,204 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { visibilityConfig: { sampledRequestsEnabled: false, cloudWatchMetricsEnabled: false, - metricName: props.config.WebAcl.Name + "-" + props.config.General.Stage + "-" + count.toString() + "-" +props.config.General.DeployHash, - } + 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++ + postProcessRuleGroups.push({ + ruleGroupType: "RuleGroup", + ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", + overrideAction: { type: "NONE" }, + }); + console.log( + " โžก๏ธ Creating " + + rulegroupidentifier + + " with calculated capacity: [" + + rulegroupcapacities[count].toString() + + "]" + ); + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[count] = + rulegroupcapacities[count]; + props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[count] = + rulegroupidentifier; + props.runtimeProperties.PostProcessDeployedRuleGroupNames[count] = name; + count++; } - const lenght = rulesets.length - props.runtimeprops.PostProcessDeployedRuleGroupCapacities.splice(lenght) - props.runtimeprops.PostProcessDeployedRuleGroupIdentifier.splice(lenght) - props.runtimeprops.PostProcessDeployedRuleGroupNames.splice(lenght) + const lenght = rulesets.length; + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.splice( + lenght + ); + props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.splice( + lenght + ); + props.runtimeProperties.PostProcessDeployedRuleGroupNames.splice(lenght); new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupNames", { - value: props.runtimeprops.PostProcessDeployedRuleGroupNames.toString(), + value: + props.runtimeProperties.PostProcessDeployedRuleGroupNames.toString(), description: "PostProcessDeployedRuleGroupNames", - exportName: "PostProcessDeployedRuleGroupNames"+props.config.General.DeployHash, + exportName: + "PostProcessDeployedRuleGroupNames" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupIdentifier", { - value: props.runtimeprops.PostProcessDeployedRuleGroupIdentifier.toString(), + value: + props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.toString(), description: "PostProcessDeployedRuleGroupIdentifier", - exportName: "PostProcessDeployedRuleGroupIdentifier"+props.config.General.DeployHash, + exportName: + "PostProcessDeployedRuleGroupIdentifier" + + props.config.General.DeployHash, }); new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupCapacities", { - value: props.runtimeprops.PostProcessDeployedRuleGroupCapacities.toString(), + value: + props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.toString(), description: "PostProcessDeployedRuleGroupCapacities", - exportName: "PostProcessDeployedRuleGroupCapacities"+props.config.General.DeployHash, + 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{ + const novalue = null; + if (!props.config.WebAcl.PostProcess.ManagedRuleGroups) { + console.log("\nโ„น๏ธ No ManagedRuleGroups defined in PostProcess."); + } else { let mangedrule; - for(mangedrule of props.config.WebAcl.PostProcess.ManagedRuleGroups){ + for (mangedrule of props.config.WebAcl.PostProcess.ManagedRuleGroups) { let ExcludeRules; let OverrideAction; - if(mangedrule.ExcludeRules){ - ExcludeRules = toCamel(mangedrule.ExcludeRules) - OverrideAction = mangedrule.OverrideAction + if (mangedrule.ExcludeRules) { + ExcludeRules = toAwsCamel(mangedrule.ExcludeRules); + OverrideAction = mangedrule.OverrideAction; + } else { + ExcludeRules = []; + OverrideAction = { type: "NONE" }; } - else{ - ExcludeRules = [] - OverrideAction = { "type": "NONE" } + if (mangedrule.Version === "") { + postProcessRuleGroups.push({ + managedRuleGroupIdentifier: { + vendorName: mangedrule.Vendor, + managedRuleGroupName: mangedrule.Name, + version: novalue, + }, + overrideAction: OverrideAction, + ruleGroupArn: novalue, + excludeRules: ExcludeRules, + ruleGroupType: "ManagedRuleGroup", + }); + } else { + postProcessRuleGroups.push({ + managedRuleGroupIdentifier: { + vendorName: mangedrule.Vendor, + managedRuleGroupName: mangedrule.Name, + version: mangedrule.Version, + }, + overrideAction: OverrideAction, + ruleGroupArn: novalue, + excludeRules: ExcludeRules, + ruleGroupType: "ManagedRuleGroup", + }); } - if(mangedrule.Version === ""){ - postProcessRuleGroups.push({"managedRuleGroupIdentifier": {"vendorName": mangedrule.Vendor, - "managedRuleGroupName":mangedrule.Name,"version": novalue},"overrideAction": OverrideAction, - "ruleGroupArn": novalue,"excludeRules": ExcludeRules,"ruleGroupType": "ManagedRuleGroup"});} - else{ - 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{ + if (!props.config.WebAcl.PreProcess.ManagedRuleGroups) { + console.log("โ„น๏ธ No ManagedRuleGroups defined in PreProcess."); + } else { let mangedrule; - for(mangedrule of props.config.WebAcl.PreProcess.ManagedRuleGroups){ + 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" }, - "preProcessRuleGroups": preProcessRuleGroups, - "postProcessRuleGroups": [], - "overrideCustomerWebACLAssociation":true, - "loggingConfiguration": { - "logDestinationConfigs":["${S3DeliveryStream.Arn}"] + if (mangedrule.ExcludeRules) { + PreProcessExcludeRules = toAwsCamel(mangedrule.ExcludeRules); + OverrideAction = mangedrule.OverrideAction; + } else { + PreProcessExcludeRules = []; + OverrideAction = { type: "NONE" }; } - } - 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}"] + 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", + }); } } - 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))} - }); } + const securityservicepolicydata = { + type: "WAFV2", + defaultAction: { + type: "ALLOW", + }, + preProcessRuleGroups, + 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) + ), + }, + }); } - const options = { flag : "w", force: true }; + const options = { flag: "w", force: true }; (async () => { try { if (process.env.PROCESS_PARAMETERS) { - await fsp.writeFile(process.env.PROCESS_PARAMETERS,JSON.stringify(props.config,null,2),options); + await fsp.writeFile( + process.env.PROCESS_PARAMETERS, + JSON.stringify(props.config, null, 2), + options + ); } } catch (error) { - console.log("Error " + error) + console.log("Error " + error); } })(); } - } \ No newline at end of file diff --git a/lib/tools/camel-case.ts b/lib/tools/camel-case.ts deleted file mode 100644 index be7d4423..00000000 --- a/lib/tools/camel-case.ts +++ /dev/null @@ -1,39 +0,0 @@ -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/tools/helpers.ts b/lib/tools/helpers.ts new file mode 100644 index 00000000..381f88c2 --- /dev/null +++ b/lib/tools/helpers.ts @@ -0,0 +1,529 @@ +import { WAFV2Client, 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"; +import { Rule } from "../types/config"; +import * as lodash from "lodash"; +import { RuntimeProperties } from "../types/runtimeprops"; +import { Config } from "../types/config"; + +/** + * Service Quota Code for Firewall Manager Total WAF WCU in account & region + */ +const WCU_QUOTA_CODE = "L-D86ED2F3"; + +/** + * Service Quota Code for Firewall Manager policies per organization per Region + */ +const POLICY_QUOTA_CODE = "L-0B28E140"; + +/** + * Get the current count of security policies in the deployment account and region + * @param deploymentRegion + * @returns A promise with the current policy count + */ +async function getPolicyCount(deploymentRegion: string): Promise { + const client = new FMSClient({ region: deploymentRegion }); + const input: ListPoliciesCommandInput = { + }; + const command = new ListPoliciesCommand(input); + const response = await client.send(command); + return response.PolicyList?.length || 0; +} + +/** + * + * @param deploymentRegion AWS region, e.g. eu-central-1 + * @param scope whether scope is REGIONAL or CLOUDFRONT + * @param rules rules for which you want to calculate the capacity + * @returns the total capacity of the supplied rules + */ +async function getTotalCapacityOfRules(deploymentRegion: string, scope: "REGIONAL" | "CLOUDFRONT", rules: Rule[]): Promise { + const client = new WAFV2Client({ region: deploymentRegion }); + const input: CheckCapacityCommandInput = { + Scope: scope, + Rules: convertPropValuesToUint8Array(rules, "SearchString") + }; + const command = new CheckCapacityCommand(input); + const response : any = await client.send(command); + return response.Capacity || 0; +} + +/** + * + * @param deploymentRegion AWS region, e.g. eu-central-1 + * @param quotaCode AWS Quota Code for the FMS Service Quota + * @returns returns the specified quota of the FMS Service + */ +async function getFmsQuota(deploymentRegion: string, quotaCode: string): Promise{ + let current_quota = 0; + const quoata_client = new quota.ServiceQuotasClient({ region: deploymentRegion }); + const input: quota.GetAWSDefaultServiceQuotaCommandInput = { + QuotaCode: quotaCode, + ServiceCode: "fms" + }; + const command = new quota.GetAWSDefaultServiceQuotaCommand(input); + const responsequoata = await quoata_client.send(command); + if(responsequoata.Quota?.Adjustable === true){ + const input: quota.ListRequestedServiceQuotaChangeHistoryByQuotaCommandInput = { + QuotaCode: quotaCode, + ServiceCode: "fms" + }; + const command = new quota.ListRequestedServiceQuotaChangeHistoryByQuotaCommand(input); + const newquota = await quoata_client.send(command); + if(newquota.RequestedQuotas !== []){ + if(newquota.RequestedQuotas?.length || 0 === 0){ + const sortquota = lodash.sortBy(newquota.RequestedQuotas,["Created"]); + if(sortquota?.length === 1){ + if(sortquota?.[0].Status !== "APPROVED"){ + console.log("โ„น๏ธ There is an open Quota request for " + quotaCode + " but it is still not approved using DEFAULT Quota."); + current_quota = responsequoata.Quota?.Value || 0; + return current_quota; + } + if(sortquota?.[0].Status === "APPROVED"){ + current_quota = sortquota?.[0].DesiredValue || 0; + return current_quota; + } + } + } + else{ + current_quota = responsequoata.Quota?.Value || 0; + return current_quota; + } + } + else{ + current_quota = responsequoata.Quota?.Value || 0; + return current_quota; + } + } + current_quota = responsequoata.Quota?.Value || 0; + return current_quota; +} + +/** + * + * @param deploymentRegion AWS region, e.g. eu-central-1 + * @param vendor vendor of the Managed Rule Group + * @param rgName vame of the Managed Rule Group + * @param scope whether scope is REGIONAL or CLOUDFRONT + * @param version version of the Managed Rule Group + * @returns returns the capacity of the Managed Rule Group + */ +async function getManagedRuleCapacity(deploymentRegion: string, vendor: string, rgName: string, scope: string, version: string): Promise{ + const client = new WAFV2Client({ region: deploymentRegion }); + if(version === ""){ + const input: DescribeManagedRuleGroupCommandInput = { + VendorName: vendor, + Name: rgName, + Scope: scope + }; + const command = new DescribeManagedRuleGroupCommand(input); + const response: any = await client.send(command); + return response.Capacity || 0; + } + else{ + const input: DescribeManagedRuleGroupCommandInput = { + VendorName: vendor, + Name: rgName, + Scope: scope, + VersionName: version + }; + const command = new DescribeManagedRuleGroupCommand(input); + const response : any = await client.send(command); + return response.Capacity || 0; + } +} + +/** + * Writes outputs from an existing stack into the specified runtime props + * @param deploymentRegion AWS region, e.g. eu-central-1 + * @param runtimeprops runtime properties, where to write stack outputs into + * @param config the config object from the values json + */ +export async function setOutputsFromStack(deploymentRegion: string, runtimeprops: RuntimeProperties, config: Config): Promise{ + const StackName = + config.General.Prefix.toUpperCase() + + "-WAF-" + + config.WebAcl.Name.toUpperCase() + + "-" + + config.General.Stage.toUpperCase() + + "-" + + config.General.DeployHash.toUpperCase(); + + const cloudformation_client = new cloudformation.CloudFormationClient({ region: deploymentRegion }); + const params ={ + StackName + }; + const command = new cloudformation.DescribeStacksCommand(params); + const responsestack = await cloudformation_client.send(command); + if(responsestack.Stacks?.[0].StackName && responsestack.Stacks?.[0].Outputs !== undefined){ + for(const output of responsestack.Stacks?.[0].Outputs){ + if(output.OutputKey === "DeployedRuleGroupNames") + { + runtimeprops.PreProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; + } + else if(output.OutputKey === "DeployedRuleGroupIdentifier") + { + runtimeprops.PreProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; + } + else if(output.OutputKey === "DeployedRuleGroupCapacities") + { + const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; + runtimeprops.PreProcessDeployedRuleGroupCapacities = arrayOfNumbers; + } + if(output.OutputKey === "PreProcessDeployedRuleGroupNames") + { + runtimeprops.PreProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; + } + else if(output.OutputKey === "PreProcessDeployedRuleGroupIdentifier") + { + runtimeprops.PreProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; + } + else if(output.OutputKey === "PreProcessDeployedRuleGroupCapacities") + { + const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; + runtimeprops.PreProcessDeployedRuleGroupCapacities = arrayOfNumbers; + } + if(output.OutputKey === "PostProcessDeployedRuleGroupNames") + { + runtimeprops.PostProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; + } + else if(output.OutputKey === "PostProcessDeployedRuleGroupIdentifier") + { + runtimeprops.PostProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; + } + else if(output.OutputKey === "PostProcessDeployedRuleGroupCapacities") + { + const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; + runtimeprops.PostProcessDeployedRuleGroupCapacities = arrayOfNumbers; + } + } + } +} + +/** + * calculate the capacities for managed and custom rules and apply them to runtime properties + * @param config configuration object of the values.json + * @param deploymentRegion AWS region, e.g. eu-central-1 + * @param runtimeProperties runtime properties object, where to store capacities + */ +async function calculateCapacities( + config: Config, + deploymentRegion: string, + runtimeProperties: RuntimeProperties +): Promise { + + let count = 0; + if (!config.WebAcl.PreProcess.CustomRules) { + console.log( + "\n โญ Skip Rule Capacity Calculation for PreProcess Custom Rules." + ); + } else { + while (count < config.WebAcl.PreProcess.CustomRules.length) { + if ("Captcha" in config.WebAcl.PreProcess.CustomRules[count].Action) { + const rules : Rule[] = []; + const { CloudWatchMetricsEnabled, SampledRequestsEnabled } = + config.WebAcl.PreProcess.CustomRules[count].VisibilityConfig; + const rule: Rule = { + Statement: config.WebAcl.PreProcess.CustomRules[count].Statement, + Name: "Rule", + Action: config.WebAcl.PreProcess.CustomRules[count].Action, + CaptchaConfig: + config.WebAcl.PreProcess.CustomRules[count].CaptchaConfig, + VisibilityConfig: { + CloudWatchMetricsEnabled, + SampledRequestsEnabled, + MetricName: "Metric" + Math.random().toString(), + }, + }; + rules.push(rule); + const capacity = await getTotalCapacityOfRules( + deploymentRegion, + config.WebAcl.Scope, + rules + ); + runtimeProperties.PreProcessRuleCapacities.push(capacity); + } else { + const rule_calculated_capacity_json = []; + const { CloudWatchMetricsEnabled, SampledRequestsEnabled } = + config.WebAcl.PreProcess.CustomRules[count].VisibilityConfig; + const temp_template: Rule = { + Statement: config.WebAcl.PreProcess.CustomRules[count].Statement, + Name: "Rule", + Action: config.WebAcl.PreProcess.CustomRules[count].Action, + VisibilityConfig: { + CloudWatchMetricsEnabled, + SampledRequestsEnabled, + MetricName: "Metric" + Math.random().toString(), + }, + }; + rule_calculated_capacity_json.push(temp_template); + const capacity = await getTotalCapacityOfRules( + deploymentRegion, + config.WebAcl.Scope, + rule_calculated_capacity_json + ); + runtimeProperties.PreProcessRuleCapacities.push(capacity); + } + count++; + } + runtimeProperties.PreProcessCapacity = runtimeProperties.PreProcessRuleCapacities.reduce( + function (a, b) { + return a + b; + }, + 0 + ); + } + count = 0; + let PostProcessCapacity = 0; + if (!config.WebAcl.PostProcess.CustomRules) { + console.log( + "\n โญ Skip Rule Capacity Calculation for PostProcess Custom Rules." + ); + } else { + while (count < config.WebAcl.PostProcess.CustomRules.length) { + const rule_calculated_capacity_json = []; + const { CloudWatchMetricsEnabled, SampledRequestsEnabled } = + config.WebAcl.PostProcess.CustomRules[count].VisibilityConfig; + const rule: Rule = { + Statement: config.WebAcl.PostProcess.CustomRules[count].Statement, + Name: "Rule", + Action: config.WebAcl.PostProcess.CustomRules[count].Action, + VisibilityConfig: { + CloudWatchMetricsEnabled, + SampledRequestsEnabled, + MetricName: "Metric" + Math.random().toString(), + }, + }; + if ("Captcha" in config.WebAcl.PostProcess.CustomRules[count].Action) { + rule.CaptchaConfig = + config.WebAcl.PostProcess.CustomRules[count].CaptchaConfig; + } + if (config.WebAcl.PostProcess.CustomRules[count].RuleLabels) { + rule.RuleLabels = + config.WebAcl.PostProcess.CustomRules[count].RuleLabels; + } + rule_calculated_capacity_json.push(rule); + const capacity = await getTotalCapacityOfRules( + deploymentRegion, + config.WebAcl.Scope, + rule_calculated_capacity_json + ); + runtimeProperties.PostProcessRuleCapacities.push(capacity); + count++; + } + PostProcessCapacity = runtimeProperties.PostProcessRuleCapacities.reduce( + function (a, b) { + return a + b; + }, + 0 + ); + } + console.log("\n๐Ÿ‘€ Get ManagedRule Capacity:\n"); + if (!config.WebAcl.PreProcess.ManagedRuleGroups) { + console.log("\n โ„น๏ธ No ManagedRuleGroups defined in PreProcess."); + } else { + console.log(" ๐Ÿฅ‡ PreProcess: "); + for (const managedrule of config.WebAcl.PreProcess.ManagedRuleGroups) { + const capacity = await getManagedRuleCapacity( + deploymentRegion, + managedrule.Vendor, + managedrule.Name, + config.WebAcl.Scope, + managedrule.Version + ); + managedrule.Capacity = capacity; + console.log( + " โž• Capacity for " + + managedrule.Name + + " is [" + + managedrule.Capacity + + "]" + ); + runtimeProperties.ManagedRuleCapacity += capacity; + } + } + if (!config.WebAcl.PostProcess.ManagedRuleGroups) { + console.log("\n โ„น๏ธ No ManagedRuleGroups defined in PostProcess."); + } else { + console.log("\n ๐Ÿฅˆ PostProcess: "); + for (const managedrule of config.WebAcl.PostProcess.ManagedRuleGroups) { + const capacity = await getManagedRuleCapacity( + deploymentRegion, + managedrule.Vendor, + managedrule.Name, + config.WebAcl.Scope, + managedrule.Version + ); + managedrule.Capacity = capacity; + console.log( + " โž• Capacity for " + + managedrule.Name + + " is [" + + managedrule.Capacity + + "]" + ); + runtimeProperties.ManagedRuleCapacity += capacity; + } + } + runtimeProperties.PostProcessCapacity = PostProcessCapacity; +} + +/** + * The functiion calculates the current security policy count in the account & region and checks if exceeds the current quota + * @param deploymentRegion AWS region, e.g. eu-central-1 + * @returns whether policy limit is reached + */ +export async function isPolicyQuotaReached(deploymentRegion: string): Promise { + const policyCount = await getPolicyCount(deploymentRegion); + const fmsPolicyQuota = await getFmsQuota(deploymentRegion, POLICY_QUOTA_CODE); + const policyLimitReached = fmsPolicyQuota <= policyCount; + if (policyLimitReached) { + console.log( + "\n๐Ÿšจ You are about to exceed the limit for Policies per region.\n Region Quota: " + + fmsPolicyQuota + + "\n Deployed Policies: " + + policyCount + + "\n ๏น— Stopping deployment ๏น—" + ); + } + return policyLimitReached; +} + +/** + * The function checks if the total WCU of all configured rules exceeds the WCU quota in account & region + * @param deploymentRegion AWS region, e.g. eu-central-1 + * @param runtimeProps runtime properties object, where to store capacities + * @param config configuration object of the values.json + * @returns whether WCU limit is reached + */ +export async function isWcuQuotaReached(deploymentRegion: string, runtimeProps: RuntimeProperties, config: Config): Promise { + await calculateCapacities(config, deploymentRegion, runtimeProps); + const custom_capacity = runtimeProps.PreProcessCapacity + runtimeProps.PostProcessCapacity; + const total_wcu = runtimeProps.PreProcessCapacity + runtimeProps.PostProcessCapacity + runtimeProps.ManagedRuleCapacity; + const quote_wcu = await getFmsQuota(deploymentRegion, WCU_QUOTA_CODE); + const wcuLimitReached = (total_wcu > Number(quote_wcu)); + if (wcuLimitReached) { + console.log("\n๐Ÿ”Ž Capacity Check result: ๐Ÿ”ด \n ๏น— Stopping deployment ๏น—\n"); + console.log(" ๐Ÿ’ก Account WAF-WCU Quota: " +Number(quote_wcu).toString()); + console.log(" ๐Ÿงฎ Calculated Custom Rule Capacity is: [" + custom_capacity + "] \n โž• ManagedRulesCapacity: ["+ runtimeProps.ManagedRuleCapacity +"] \n ๏ผ Total Waf Capacity: " + total_wcu.toString() + "\n"); + } + else { + console.log("\n๐Ÿ”Ž Capacity Check result: ๐ŸŸข \n"); + console.log(" ๐Ÿ’ก Account WAF-WCU Quota: " +Number(quote_wcu).toString()); + console.log(" ๐Ÿงฎ Calculated Custom Rule Capacity is: [" + custom_capacity + "] (๐Ÿฅ‡[" + runtimeProps.PreProcessCapacity + "] + ๐Ÿฅˆ[" + runtimeProps.PostProcessCapacity + "]) \n โž• ManagedRulesCapacity: ["+ runtimeProps.ManagedRuleCapacity +"] \n ๏ผ Total Waf Capacity: " + total_wcu.toString() + "\n"); + } + return wcuLimitReached; +} + +/** + * initialize a runtime properties object + * @returns the runtime properties object + */ +export function initRuntimeProperties() : RuntimeProperties { + return { + ManagedRuleCapacity: 0, + PreProcessCapacity: 0, + PostProcessCapacity: 0, + PreProcessDeployedRuleGroupCapacities: [], + PreProcessRuleCapacities: [], + PreProcessDeployedRuleGroupNames: [], + PreProcessDeployedRuleGroupIdentifier: [], + PostProcessDeployedRuleGroupCapacities: [], + PostProcessRuleCapacities: [], + PostProcessDeployedRuleGroupNames: [], + PostProcessDeployedRuleGroupIdentifier: [], + }; +} + +/** + * The function converts the value of all properties with supplied name into a Uint8Array + * @param rulesObject Rules Object or Array of Rules Object + * @param propertyName name of the properties which have to be converted + * @returns converted Rules + */ +function convertPropValuesToUint8Array(rulesObject: any, propertyName: string): any { + const convertedObject: any = {}; + let value: any; + if (rulesObject instanceof Array) { + return rulesObject.map(function (value) { + if (typeof value === "object") { + value = convertPropValuesToUint8Array(value, propertyName); + } + return value; + }); + } else { + for (const origKey in rulesObject) { + if (Object.prototype.hasOwnProperty.call(rulesObject,origKey)) { + value = rulesObject[origKey]; + if (value instanceof Array || (value !== null && value.constructor === Object)) { + value = convertPropValuesToUint8Array(value, propertyName); + } + if (origKey === propertyName) { + value = convertStringToUint8Array(rulesObject[origKey]); + } + convertedObject[origKey] = value; + } + } + } + return convertedObject; +} + +/** + * The function returns Uint8 representation of a string + * @param stringToConvert string which has to be converted to Uint8Array + * @returns the desired Uint8Array representation of the string + */ +function convertStringToUint8Array(stringToConvert: string): Uint8Array { + const buf = new ArrayBuffer(stringToConvert.length * 2); // 2 bytes for each char + const bufView = new Uint8Array(buf); + for (let i = 0, strLen = stringToConvert.length; i < strLen; i++) { + bufView[i] = stringToConvert.charCodeAt(i); + } + return bufView; +} + +/** + * Function to transform property names into camel case like AWS needs it + * @param o object which property names has to be transformed to camel case + * @returns the object with the transformed property names in camel case + */ +export function toAwsCamel(o: any): any { + let newO: any, origKey: any, newKey: any, value: any; + if (o instanceof Array) { + return o.map(function(value) { + if (typeof value === "object") { + value = toAwsCamel(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 = toAwsCamel(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 4fc4eef8..d18529dc 100644 --- a/lib/types/config.ts +++ b/lib/types/config.ts @@ -1,11 +1,3 @@ -interface RulesArray{ - Name?: string, - Statement: any, - Action: any, - VisibilityConfig: any, - CaptchaConfig?: any, -} - export interface Config { readonly General: { readonly Prefix: string, @@ -18,25 +10,58 @@ export interface Config { }, readonly WebAcl:{ readonly Name: string, - readonly Scope: string, + readonly Scope: "CLOUDFRONT" | "REGIONAL", readonly Type: string, - readonly PreProcess: { - CustomRules?: Array | undefined, - ManagedRuleGroups?: any[] | undefined; - } - readonly PostProcess:{ - CustomRules?: Array | undefined, - ManagedRuleGroups?: any[] | undefined; - } + readonly PreProcess: RouleGroupSet, + readonly PostProcess: RouleGroupSet }, } +interface RouleGroupSet { + CustomRules?: Rule[], + ManagedRuleGroups?: ManagedRuleGroup[]; +} -interface RulesArray{ +interface ManagedRuleGroup { + Vendor: string, + Name: string, + Version: string, + Capacity: number, + ExcludeRules?: NameObject[], + OverrideAction?: { + type: "COUNT" | "NONE" + } +} +export interface Rule { Name?: string, Statement: any, - Action: any, - VisibilityConfig: any, - CaptchaConfig?: any, - RuleLabels?: any + Action: Action, + VisibilityConfig: { + SampledRequestsEnabled: boolean, + CloudWatchMetricsEnabled: boolean, + MetricName?: string + }, + CaptchaConfig?: { + ImmunityTimeProperty?: { + ImmunityTime: number + } + }, + RuleLabels?: NameObject[] +} + +type NameObject = { + Name: string +} + +type Action = | { + Block: Record +} +| { + Allow: Record +} +| { + Count: Record +} +| { + Captcha: Record } \ No newline at end of file diff --git a/lib/types/runtimeprops.ts b/lib/types/runtimeprops.ts index 7f08e2af..5b663669 100644 --- a/lib/types/runtimeprops.ts +++ b/lib/types/runtimeprops.ts @@ -1,6 +1,7 @@ -export interface Runtimeprops { +export interface RuntimeProperties { PreProcessCapacity: number, PostProcessCapacity: number, + ManagedRuleCapacity: number, PreProcessRuleCapacities: number[], PostProcessRuleCapacities: number[], PreProcessDeployedRuleGroupCapacities: number[], diff --git a/package.json b/package.json index 2b95ef83..c3f1679c 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,10 @@ "typescript": "~3.9.7" }, "dependencies": { - "@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.48.0", + "@aws-sdk/client-cloudformation": "^3.52.0", + "@aws-sdk/client-fms": "^3.52.0", + "@aws-sdk/client-service-quotas": "^3.52.0", + "@aws-sdk/client-wafv2": "^3.52.0", "@mhlabs/cfn-diagram": "^1.1.32", "@types/lodash": "^4.14.178", "aws-cdk-lib": "^2.8.0", @@ -40,4 +40,4 @@ "shapes": "^0.4.0", "typescript-json-schema": "^0.53.0" } -} +} \ No newline at end of file diff --git a/values/calculatecapacity.json b/values/calculatecapacity.json deleted file mode 100644 index 749981e2..00000000 --- a/values/calculatecapacity.json +++ /dev/null @@ -1,16 +0,0 @@ -{ -"Name": "TEST", -"Priority": 0, -"Statement": { -}, -"Action":{ -}, -"CaptchaConfig":{ -}, -"VisibilityConfig": { - "SampledRequestsEnabled": false, - "CloudWatchMetricsEnabled": false, - "MetricName": "TEST" -}, -"RuleLabels": [] -} From 76cfc54fd479d78bdb1a2f39c16b99f13651e247 Mon Sep 17 00:00:00 2001 From: Marcell Jobs <31279340+kirnberger1980@users.noreply.github.com> Date: Thu, 24 Feb 2022 18:58:16 +0100 Subject: [PATCH 2/4] Add missing ajv dependency --- cdk.out/cdk.out | 2 +- lib/tools/config-validator.ts | 2 +- package.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cdk.out/cdk.out b/cdk.out/cdk.out index c1ee7b9a..5bdbc9d3 100644 --- a/cdk.out/cdk.out +++ b/cdk.out/cdk.out @@ -1 +1 @@ -{"version":"14.0.0"} \ No newline at end of file +{"version":"16.0.0"} \ No newline at end of file diff --git a/lib/tools/config-validator.ts b/lib/tools/config-validator.ts index d39df9b5..60cae837 100644 --- a/lib/tools/config-validator.ts +++ b/lib/tools/config-validator.ts @@ -1,4 +1,4 @@ -import Ajv, {JSONSchemaType} from "ajv" +import Ajv, {JSONSchemaType} from "ajv"; import {Config} from "../types/config"; import { resolve } from "path"; import * as TJS from "typescript-json-schema"; diff --git a/package.json b/package.json index c3f1679c..90bdf7e1 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@aws-sdk/client-wafv2": "^3.52.0", "@mhlabs/cfn-diagram": "^1.1.32", "@types/lodash": "^4.14.178", + "ajv": "^8.10.0", "aws-cdk-lib": "^2.8.0", "constructs": "^10.0.0", "lodash": "^4.17.21", @@ -40,4 +41,4 @@ "shapes": "^0.4.0", "typescript-json-schema": "^0.53.0" } -} \ No newline at end of file +} From b35f8c0501af9537245dfce870bd5b0a0aec973e Mon Sep 17 00:00:00 2001 From: Marcell Jobs <31279340+kirnberger1980@users.noreply.github.com> Date: Mon, 28 Feb 2022 16:30:04 +0100 Subject: [PATCH 3/4] Continue Refactoring (Part 1) - adding 2 functions for building service data (managed & custom rules) to remove redundant code - restructuring runtime properties: introduce separate layer for PreProcess and PostProcess - new types for Firewall Manager API and CDK mapping --- lib/plattform-wafv2-cdk-automation-stack.ts | 1717 ++++++------------- lib/tools/helpers.ts | 62 +- lib/types/config.ts | 51 +- lib/types/fms.ts | 79 + lib/types/runtimeprops.ts | 22 +- 5 files changed, 657 insertions(+), 1274 deletions(-) create mode 100644 lib/types/fms.ts diff --git a/lib/plattform-wafv2-cdk-automation-stack.ts b/lib/plattform-wafv2-cdk-automation-stack.ts index 3f598c0e..34f3b5b8 100644 --- a/lib/plattform-wafv2-cdk-automation-stack.ts +++ b/lib/plattform-wafv2-cdk-automation-stack.ts @@ -6,7 +6,8 @@ import { aws_kinesisfirehose as firehouse } from "aws-cdk-lib"; import { aws_iam as iam } from "aws-cdk-lib"; import { aws_logs as logs } from "aws-cdk-lib"; import { Config } from "./types/config"; -import { RuntimeProperties } from "./types/runtimeprops"; +import { ManagedRuleGroup, ManagedServiceData, ServiceDataManagedRuleGroup, ServiceDataRuleGroup, Rule } from "./types/fms"; +import { RuntimeProperties, ProcessProperties } from "./types/runtimeprops"; import { promises as fsp } from "fs"; import { toAwsCamel } from "./tools/helpers"; @@ -101,1239 +102,581 @@ export class PlattformWafv2CdkAutomationStack extends cdk.Stack { }, }); - if ( - !props.config.WebAcl.PreProcess.CustomRules && - !props.config.WebAcl.PostProcess.CustomRules - ) { - console.log("Creating DEFAULT Policy."); - const novalue = null; - let mangedrule; - let ExcludeRules; - let OverrideAction; - const preProcessRuleGroups = []; - const postProcessRuleGroups = []; - if (!props.config.WebAcl.PreProcess.ManagedRuleGroups) { - console.log("\nโ„น๏ธ No ManagedRuleGroups defined in PreProcess."); - } else { - for (mangedrule of props.config.WebAcl.PreProcess.ManagedRuleGroups) { - if (mangedrule.ExcludeRules) { - ExcludeRules = toAwsCamel(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", - }); - } - } - } - if (!props.config.WebAcl.PostProcess.ManagedRuleGroups) { - console.log("โ„น๏ธ No ManagedRuleGroups defined in PostProcess."); - } else { - for (mangedrule of props.config.WebAcl.PostProcess.ManagedRuleGroups) { - if (mangedrule.ExcludeRules) { - ExcludeRules = toAwsCamel(mangedrule.ExcludeRules); - OverrideAction = mangedrule.OverrideAction; - } else { - ExcludeRules = []; - OverrideAction = { type: "NONE" }; - } - if (mangedrule.Version === "") { - postProcessRuleGroups.push({ - managedRuleGroupIdentifier: { - vendorName: mangedrule.Vendor, - managedRuleGroupName: mangedrule.Name, - version: novalue, - }, - overrideAction: OverrideAction, - ruleGroupArn: novalue, - excludeRules: ExcludeRules, - ruleGroupType: "ManagedRuleGroup", - }); - } else { - postProcessRuleGroups.push({ - managedRuleGroupIdentifier: { - vendorName: mangedrule.Vendor, - managedRuleGroupName: mangedrule.Name, - version: mangedrule.Version, - }, - overrideAction: OverrideAction, - ruleGroupArn: novalue, - excludeRules: ExcludeRules, - ruleGroupType: "ManagedRuleGroup", - }); - } + const preProcessRuleGroups = []; + const postProcessRuleGroups = []; + console.log("Creating DEFAULT Policy."); + if (props.config.WebAcl.PreProcess.ManagedRuleGroups) { + preProcessRuleGroups.push(...buildServiceDataManagedRGs(props.config.WebAcl.PreProcess.ManagedRuleGroups)); + } else { + console.log("\nโ„น๏ธ No ManagedRuleGroups defined in PreProcess."); + } + if (props.config.WebAcl.PostProcess.ManagedRuleGroups) { + postProcessRuleGroups.push(...buildServiceDataManagedRGs(props.config.WebAcl.PostProcess.ManagedRuleGroups)); + } else { + console.log("โ„น๏ธ No ManagedRuleGroups defined in PostProcess."); + } + if (props.config.WebAcl.PreProcess.CustomRules) { + const customRgs = buildServiceDataCustomRGs(this, "Pre", props.runtimeProperties.PreProcess.Capacity, props.config.General.DeployHash, props.config.WebAcl.Name, props.config.WebAcl.Scope, props.config.General.Stage, props.runtimeProperties.PreProcess, props.config.General.Prefix, props.config.WebAcl.PreProcess.CustomRules); + preProcessRuleGroups.push(...customRgs); + } else { + console.log("\nโ„น๏ธ No Custom Rules defined in PreProcess."); + } + if (props.config.WebAcl.PostProcess.CustomRules) { + const customRgs = buildServiceDataCustomRGs(this, "Post", props.runtimeProperties.PostProcess.Capacity, props.config.General.DeployHash, props.config.WebAcl.Name, props.config.WebAcl.Scope, props.config.General.Stage, props.runtimeProperties.PostProcess, props.config.General.Prefix, props.config.WebAcl.PostProcess.CustomRules); + postProcessRuleGroups.push(...customRgs); + } else { + console.log("\nโ„น๏ธ No Custom Rules defined in PostProcess."); + } + + const managedServiceData : ManagedServiceData = { + 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, + 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(managedServiceData) + ), + }, + }); + + const options = { flag: "w", force: true }; + (async () => { + try { + 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); } - 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, - policyName: - props.config.General.Prefix.toUpperCase() + +function buildServiceDataManagedRGs(managedRuleGroups: ManagedRuleGroup[]) : ServiceDataManagedRuleGroup[] { + const cfnManagedRuleGroup : ServiceDataManagedRuleGroup[] = []; + for (const managedRuleGroup of managedRuleGroups) { + cfnManagedRuleGroup.push({ + managedRuleGroupIdentifier: { + vendorName: managedRuleGroup.Vendor, + managedRuleGroupName: managedRuleGroup.Name, + version: managedRuleGroup.Version !== "" ? managedRuleGroup.Version : null, + }, + overrideAction: managedRuleGroup.ExcludeRules && managedRuleGroup.OverrideAction ? managedRuleGroup.OverrideAction : { type: "NONE" }, + ruleGroupArn: null, + excludeRules: managedRuleGroup.ExcludeRules ? toAwsCamel(managedRuleGroup.ExcludeRules) : [], + ruleGroupType: "ManagedRuleGroup" + }); + } + return cfnManagedRuleGroup; +} + +function buildServiceDataCustomRGs(scope: Construct, type: "Pre" | "Post", capacity: number, deployHash: string, webaclName: string, webAclScope: string, stage: string, processRuntimeProps: ProcessProperties, prefix: string, ruleGroupSet: Rule[]) : ServiceDataRuleGroup[] { + const serviceDataRuleGroup : ServiceDataRuleGroup[] = []; + let icon; + if (type === "Pre") { + icon = "๐Ÿฅ‡ "; + } else { + icon = "๐Ÿฅˆ"; + } + console.log( + "\u001b[1m", + "\n"+icon+" Custom Rules " + type + "Process: ", + "\x1b[0m\n" + ); + if (capacity < 1000) { + const rules = []; + let count = 1; + for (const statement of ruleGroupSet) { + let rulename = ""; + if (statement.Name !== undefined) { + rulename = + statement.Name + "-" + type.toLocaleLowerCase() + "-" + deployHash; + } else { + rulename = + webaclName + "-" + - props.config.WebAcl.Name + + type.toLocaleLowerCase() + "-" + - props.config.General.Stage + + stage + "-" + - props.config.General.DeployHash, - includeMap: { account: props.config.General.DeployTo }, - securityServicePolicyData: { - Type: "WAFV2", - ManagedServiceData: cdk.Fn.sub( - JSON.stringify(securityservicepolicydata) - ), - }, - }); - } else { - const preProcessRuleGroups = []; - const postProcessRuleGroups = []; - if (!props.config.WebAcl.PreProcess.CustomRules) { - console.log("\nโ„น๏ธ No Custom Rules defined in PreProcess."); + count.toString() + + "-" + + deployHash; + } + let CfnRuleProperty; + if ("Captcha" in statement.Action) { + CfnRuleProperty = { + name: rulename, + priority: count, + action: toAwsCamel(statement.Action), + statement: toAwsCamel(statement.Statement), + visibilityConfig: { + sampledRequestsEnabled: + statement.VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: + statement.VisibilityConfig.CloudWatchMetricsEnabled, + metricName: rulename + "-metric", + }, + captchaConfig: toAwsCamel(statement.CaptchaConfig), + ruleLabels: toAwsCamel(statement.RuleLabels), + }; + } else { + CfnRuleProperty = { + name: rulename, + priority: count, + action: toAwsCamel(statement.Action), + statement: toAwsCamel(statement.Statement), + visibilityConfig: { + sampledRequestsEnabled: + statement.VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: + statement.VisibilityConfig.CloudWatchMetricsEnabled, + metricName: rulename + "-metric", + }, + ruleLabels: toAwsCamel(statement.RuleLabels), + }; + } + let CfnRuleProperties: wafv2.CfnRuleGroup.RuleProperty; + if (statement.RuleLabels) { + CfnRuleProperties = CfnRuleProperty; } else { + const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty; + CfnRuleProperties = CfnRulePropertii; + } + rules.push(CfnRuleProperties); + count += 1; + } + + let name = + webaclName + + "-"+type.toLocaleLowerCase()+"-" + + stage + + "-" + + deployHash; + let rulegroupidentifier = type + "RuleGroup"; + if (processRuntimeProps.DeployedRuleGroupCapacities[0]) { + if ( + processRuntimeProps.DeployedRuleGroupCapacities[0] !== + capacity + ) { console.log( - "\u001b[1m", - "\n๐Ÿฅ‡ Custom Rules PreProcess: ", - "\x1b[0m\n" + "โญ•๏ธ Deploy new RuleGroup because the Capacity has changed!" ); - if (props.runtimeProperties.PreProcessCapacity < 1000) { - const rules = []; - let count = 1; - for (const statement of props.config.WebAcl.PreProcess.CustomRules) { - let rulename = ""; - if (statement.Name !== undefined) { - rulename = - statement.Name + "-pre-" + props.config.General.DeployHash; - } else { - rulename = - props.config.WebAcl.Name + - "-pre-" + - props.config.General.Stage + - "-" + - count.toString() + - "-" + - props.config.General.DeployHash; - } - let CfnRuleProperty; - if ("Captcha" in statement.Action) { - CfnRuleProperty = { - name: rulename, - priority: count, - action: toAwsCamel(statement.Action), - statement: toAwsCamel(statement.Statement), - visibilityConfig: { - sampledRequestsEnabled: - statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: - statement.VisibilityConfig.CloudWatchMetricsEnabled, - metricName: rulename + "-metric", - }, - captchaConfig: toAwsCamel(statement.CaptchaConfig), - ruleLabels: toAwsCamel(statement.RuleLabels), - }; - } else { - CfnRuleProperty = { - name: rulename, - priority: count, - action: toAwsCamel(statement.Action), - statement: toAwsCamel(statement.Statement), - visibilityConfig: { - sampledRequestsEnabled: - statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: - statement.VisibilityConfig.CloudWatchMetricsEnabled, - metricName: rulename + "-metric", - }, - ruleLabels: toAwsCamel(statement.RuleLabels), - }; - } - let CfnRuleProperties: wafv2.CfnRuleGroup.RuleProperty; - if (statement.RuleLabels) { - CfnRuleProperties = CfnRuleProperty; - } else { - const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty; - CfnRuleProperties = CfnRulePropertii; - } - rules.push(CfnRuleProperties); - count += 1; - } + console.log( + "\n ๐ŸŸฅ Old Capacity: [" + + processRuntimeProps.DeployedRuleGroupCapacities[0] + + "]\n ๐ŸŸฉ New Capacity: [" + + processRuntimeProps.Capacity + + "]" + ); + if ( + processRuntimeProps.DeployedRuleGroupIdentifier[0] === + "RuleGroup" + ) { + rulegroupidentifier = type + "RG"; + } - let name = - props.config.WebAcl.Name + - "-pre-" + - props.config.General.Stage + + if ( + processRuntimeProps.DeployedRuleGroupNames[0] === + webaclName + "-" + - props.config.General.DeployHash; - let rulegroupidentifier = "PreRuleGroup"; - if ( - typeof props.runtimeProperties - .PreProcessDeployedRuleGroupCapacities[0] !== "undefined" - ) { - if ( - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[0] !== - props.runtimeProperties.PreProcessCapacity - ) { - console.log( - "โญ•๏ธ Deploy new RuleGroup because the Capacity has changed!" - ); - console.log( - "\n ๐ŸŸฅ Old Capacity: [" + - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[0] + - "]\n ๐ŸŸฉ New Capacity: [" + - props.runtimeProperties.PreProcessCapacity + - "]" - ); - if ( - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[0] === - "RuleGroup" - ) { - rulegroupidentifier = "preRG"; - } - - if ( - props.runtimeProperties.PreProcessDeployedRuleGroupNames[0] === - props.config.WebAcl.Name + - "-" + - props.config.General.Stage + - "-" + - props.config.General.DeployHash - ) { - name = - props.config.General.Prefix.toUpperCase() + - "-G" + - props.config.WebAcl.Name + - "-" + - props.config.General.Stage + - "-" + - props.config.General.DeployHash; - } - console.log(" ๐Ÿ’ฌ New Name: " + name); - console.log(" ๐Ÿ“‡ New Identifier: " + rulegroupidentifier); - } - } - new wafv2.CfnRuleGroup(this, rulegroupidentifier, { - capacity: props.runtimeProperties.PreProcessCapacity, - scope: props.config.WebAcl.Scope, - rules: rules, - name: name, - visibilityConfig: { - sampledRequestsEnabled: false, - cloudWatchMetricsEnabled: false, - metricName: - props.config.General.Prefix.toUpperCase() + - "-" + - props.config.WebAcl.Name + - "-" + - props.config.General.Stage + - "-" + - props.config.General.DeployHash, - }, - }); - preProcessRuleGroups.push({ - ruleGroupType: "RuleGroup", - ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", - overrideAction: { type: "NONE" }, - }); - console.log( - " โžก๏ธ Creating " + - rulegroupidentifier + - " with calculated capacity: [" + - props.runtimeProperties.PreProcessCapacity + - "]" - ); - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.splice(0); - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.splice(0); - props.runtimeProperties.PreProcessDeployedRuleGroupNames.splice(0); - - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[0] = - rulegroupidentifier; - props.runtimeProperties.PreProcessDeployedRuleGroupNames[0] = name; - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[0] = - props.runtimeProperties.PreProcessCapacity; - - new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupNames", { - value: - props.runtimeProperties.PreProcessDeployedRuleGroupNames.toString(), - description: "PreProcessDeployedRuleGroupNames", - exportName: - "PreProcessDeployedRuleGroupNames" + - props.config.General.DeployHash, - }); + stage + + "-" + + deployHash + ) { + name = + prefix.toUpperCase() + + "-G" + + webaclName + + "-" + + stage + + "-" + + deployHash; + } + console.log(" ๐Ÿ’ฌ New Name: " + name); + console.log(" ๐Ÿ“‡ New Identifier: " + rulegroupidentifier); + } + } + new wafv2.CfnRuleGroup(scope, rulegroupidentifier, { + capacity: processRuntimeProps.Capacity, + scope: webAclScope, + rules: rules, + name: name, + visibilityConfig: { + sampledRequestsEnabled: false, + cloudWatchMetricsEnabled: false, + metricName: + prefix.toUpperCase() + + "-" + + webaclName + + "-" + + stage + + "-" + + deployHash, + }, + }); + serviceDataRuleGroup.push({ + ruleGroupType: "RuleGroup", + ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", + overrideAction: { type: "NONE" }, + }); + console.log( + " โžก๏ธ Creating " + + rulegroupidentifier + + " with calculated capacity: [" + + processRuntimeProps.Capacity + + "]" + ); + processRuntimeProps.DeployedRuleGroupCapacities.splice(0); + processRuntimeProps.DeployedRuleGroupIdentifier.splice(0); + processRuntimeProps.DeployedRuleGroupNames.splice(0); + + processRuntimeProps.DeployedRuleGroupIdentifier[0] = + rulegroupidentifier; + processRuntimeProps.DeployedRuleGroupNames[0] = name; + processRuntimeProps.DeployedRuleGroupCapacities[0] = + processRuntimeProps.Capacity; + + new cdk.CfnOutput(scope, "PreProcessDeployedRuleGroupNames", { + value: + processRuntimeProps.DeployedRuleGroupNames.toString(), + description: "PreProcessDeployedRuleGroupNames", + exportName: + "PreProcessDeployedRuleGroupNames" + + deployHash, + }); - new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupCapacities", { - value: - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.toString(), - description: "PreProcessDeployedRuleGroupCapacities", - exportName: - "PreProcessDeployedRuleGroupCapacities" + - props.config.General.DeployHash, - }); + new cdk.CfnOutput(scope, "PreProcessDeployedRuleGroupCapacities", { + value: + processRuntimeProps.DeployedRuleGroupCapacities.toString(), + description: "PreProcessDeployedRuleGroupCapacities", + exportName: + "PreProcessDeployedRuleGroupCapacities" + + deployHash, + }); - new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupIdentifier", { - value: - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.toString(), - description: "PreProcessDeployedRuleGroupIdentifier", - exportName: - "PreProcessDeployedRuleGroupIdentifier" + - props.config.General.DeployHash, - }); - } else { - const threshold = 1000; - const rulesets: any[] = []; - const indexes: number[] = []; - const rulegroupcapacities = []; - while ( - indexes.length < props.runtimeProperties.PreProcessRuleCapacities.length - ) { - let tracker = 0; - const ruleset: any[] = []; - props.runtimeProperties.PreProcessRuleCapacities.map((v, i) => { - 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(scope, "PreProcessDeployedRuleGroupIdentifier", { + value: + processRuntimeProps.DeployedRuleGroupIdentifier.toString(), + description: "PreProcessDeployedRuleGroupIdentifier", + exportName: + "PreProcessDeployedRuleGroupIdentifier" + + deployHash, + }); + } else { + const threshold = 1000; + const rulesets: any[] = []; + const indexes: number[] = []; + const rulegroupcapacities = []; + while ( + indexes.length < processRuntimeProps.RuleCapacities.length + ) { + let tracker = 0; + const ruleset: any[] = []; + processRuntimeProps.RuleCapacities.map((v, i) => { + 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); + } + console.log( + ` ๐Ÿ–– Split Rules into ${rulesets.length.toString()} RuleGroups: \n` + ); + let count = 0; + let rulegroupidentifier = ""; + let name = ""; + while (count < rulesets.length) { + if (processRuntimeProps.DeployedRuleGroupCapacities[count]) { + if ( + rulegroupcapacities[count] === + processRuntimeProps.DeployedRuleGroupCapacities[count] + ) { + rulegroupidentifier = type + "R" + count.toString(); + name = + webaclName + + "-" + + type.toLocaleLowerCase() + + "-" + + stage + + "-" + + count.toString() + + "-" + + deployHash; + } else { console.log( - ` ๐Ÿ–– Split Rules into ${rulesets.length.toString()} RuleGroups: \n` + "\nโญ•๏ธ Deploy new RuleGroup because the Capacity has changed for " + + processRuntimeProps.DeployedRuleGroupIdentifier[ + count + ] + + " !" + ); + console.log( + "\n ๐ŸŸฅ Old Capacity: [" + + processRuntimeProps.DeployedRuleGroupCapacities[ + count + ] + + "]\n ๐ŸŸฉ New Capacity: [" + + rulegroupcapacities[count] + + "]" ); - let count = 0; - let rulegroupidentifier = ""; - let name = ""; - while (count < rulesets.length) { + if (processRuntimeProps.DeployedRuleGroupCapacities[count]) { if ( - typeof props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[ + processRuntimeProps.DeployedRuleGroupNames[ count - ] !== "undefined" + ] === + webaclName + + "-" + + stage + + "-" + + count.toString() + + "-" + + deployHash ) { - if ( - rulegroupcapacities[count] === - props.runtimeProperties.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.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[ - count - ] + - " !" - ); - console.log( - "\n ๐ŸŸฅ Old Capacity: [" + - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities[ - count - ] + - "]\n ๐ŸŸฉ New Capacity: [" + - rulegroupcapacities[count] + - "]" - ); - if ( - typeof props.runtimeProperties - .PreProcessDeployedRuleGroupCapacities[count] !== - "undefined" - ) { - if ( - props.runtimeProperties.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); - } - if ( - typeof props.runtimeProperties - .PreProcessDeployedRuleGroupIdentifier[count] !== undefined - ) { - if ( - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[ - count - ] === - "R" + count.toString() - ) { - rulegroupidentifier = "preG" + count.toString(); - } else { - rulegroupidentifier = "preR" + count.toString(); - } - console.log( - " ๐Ÿ“‡ New Identifier: " + rulegroupidentifier + "\n" - ); - } - } - } else { - rulegroupidentifier = "preR" + count.toString(); name = - props.config.WebAcl.Name + - "-" + - props.config.General.Stage + + webaclName + "-" + + stage + + "-"+ type.toLocaleLowerCase() + "R-" + 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: toAwsCamel( - props.config.WebAcl.PreProcess.CustomRules[statementindex] - .Action - ), - statement: toAwsCamel( - 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: toAwsCamel( - props.config.WebAcl.PreProcess.CustomRules[statementindex] - .CaptchaConfig - ), - ruleLabels: toAwsCamel( - props.config.WebAcl.PreProcess.CustomRules[statementindex] - .RuleLabels - ), - }; - } else { - CfnRuleProperty = { - name: rulename, - priority: rulegroupcounter, - action: toAwsCamel( - props.config.WebAcl.PreProcess.CustomRules[statementindex] - .Action - ), - statement: toAwsCamel( - 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: toAwsCamel( - props.config.WebAcl.PreProcess.CustomRules[statementindex] - .RuleLabels - ), - }; - } - 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++; - } - 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.runtimeProperties.PreProcessDeployedRuleGroupCapacities[count] = - rulegroupcapacities[count]; - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier[count] = - rulegroupidentifier; - props.runtimeProperties.PreProcessDeployedRuleGroupNames[count] = name; - count++; - } - const lenght = rulesets.length; - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.splice( - lenght - ); - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.splice( - lenght - ); - props.runtimeProperties.PreProcessDeployedRuleGroupNames.splice(lenght); - - new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupNames", { - value: - props.runtimeProperties.PreProcessDeployedRuleGroupNames.toString(), - description: "PreProcessDeployedRuleGroupNames", - exportName: - "PreProcessDeployedRuleGroupNames" + - props.config.General.DeployHash, - }); - - new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupCapacities", { - value: - props.runtimeProperties.PreProcessDeployedRuleGroupCapacities.toString(), - description: "PreProcessDeployedRuleGroupCapacities", - exportName: - "PreProcessDeployedRuleGroupCapacities" + - props.config.General.DeployHash, - }); - - new cdk.CfnOutput(this, "PreProcessDeployedRuleGroupIdentifier", { - value: - props.runtimeProperties.PreProcessDeployedRuleGroupIdentifier.toString(), - description: "PreProcessDeployedRuleGroupIdentifier", - exportName: - "PreProcessDeployedRuleGroupIdentifier" + - props.config.General.DeployHash, - }); - } - } - if (!props.config.WebAcl.PostProcess.CustomRules) { - console.log("\nโ„น๏ธ No Custom Rules defined in PostProcess."); - } else { - console.log( - "\u001b[1m", - "\n๐Ÿฅˆ Custom Rules PostProcess:", - "\x1b[0m\n" - ); - if (props.runtimeProperties.PostProcessCapacity < 1000) { - const rules = []; - let count = 1; - - for (const statement of props.config.WebAcl.PostProcess.CustomRules) { - let rulename = ""; - if (statement.Name !== undefined) { - rulename = - statement.Name + "-post-" + props.config.General.DeployHash; + deployHash; } else { - rulename = - props.config.WebAcl.Name + + name = + webaclName + "-" + - props.config.General.Stage + - "-post-" + + stage + + "-"+ type.toLocaleLowerCase() +"-" + count.toString() + "-" + - props.config.General.DeployHash; - } - let CfnRuleProperty; - if ("Captcha" in statement.Action) { - CfnRuleProperty = { - name: rulename, - priority: count, - action: toAwsCamel(statement.Action), - statement: toAwsCamel(statement.Statement), - visibilityConfig: { - sampledRequestsEnabled: - statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: - statement.VisibilityConfig.CloudWatchMetricsEnabled, - metricName: rulename + "-metric", - }, - captchaConfig: toAwsCamel(statement.CaptchaConfig), - ruleLabels: toAwsCamel(statement.RuleLabels), - }; - } else { - CfnRuleProperty = { - name: rulename, - priority: count, - action: toAwsCamel(statement.Action), - statement: toAwsCamel(statement.Statement), - visibilityConfig: { - sampledRequestsEnabled: - statement.VisibilityConfig.SampledRequestsEnabled, - cloudWatchMetricsEnabled: - statement.VisibilityConfig.CloudWatchMetricsEnabled, - metricName: rulename + "-metric", - }, - ruleLabels: toAwsCamel(statement.RuleLabels), - }; - } - let CfnRuleProperti: wafv2.CfnRuleGroup.RuleProperty; - if (statement.RuleLabels) { - CfnRuleProperti = CfnRuleProperty; - } else { - const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty; - CfnRuleProperti = CfnRulePropertii; + deployHash; } - rules.push(CfnRuleProperti); - count += 1; - } - - let name = - props.config.WebAcl.Name + - "-post-" + - props.config.General.Stage + - "-" + - props.config.General.DeployHash; - let rulegroupidentifier = "PostRuleGroup"; - if ( - typeof props.runtimeProperties - .PostProcessDeployedRuleGroupCapacities[0] !== "undefined" - ) { - if ( - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[0] !== - props.runtimeProperties.PostProcessCapacity - ) { - console.log( - "โญ•๏ธ Deploy new RuleGroup because the Capacity has changed!" - ); - console.log( - "\n ๐ŸŸฅ Old Capacity: [" + - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[0] + - "]\n ๐ŸŸฉ New Capacity: [" + - props.runtimeProperties.PostProcessCapacity + - "]" - ); - if ( - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[0] === - "PostRuleGroup" - ) { - rulegroupidentifier = "postRG"; - } - if ( - props.runtimeProperties.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); - } - } - new wafv2.CfnRuleGroup(this, rulegroupidentifier, { - capacity: props.runtimeProperties.PostProcessCapacity, - scope: props.config.WebAcl.Scope, - rules: rules, - name: name, - visibilityConfig: { - sampledRequestsEnabled: false, - cloudWatchMetricsEnabled: false, - metricName: name + "-metric", - }, - }); - postProcessRuleGroups.push({ - ruleGroupType: "RuleGroup", - ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", - overrideAction: { type: "NONE" }, - }); - console.log( - " โžก๏ธ Creating " + - rulegroupidentifier + - " with calculated capacity: [" + - props.runtimeProperties.PostProcessCapacity + - "]" - ); - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.splice(0); - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.splice(0); - props.runtimeProperties.PostProcessDeployedRuleGroupNames.splice(0); - - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[0] = - rulegroupidentifier; - props.runtimeProperties.PostProcessDeployedRuleGroupNames[0] = name; - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[0] = - props.runtimeProperties.PostProcessCapacity; - - new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupNames", { - value: - props.runtimeProperties.PostProcessDeployedRuleGroupNames.toString(), - description: "PostProcessDeployedRuleGroupNames", - exportName: - "PostProcessDeployedRuleGroupNames" + - props.config.General.DeployHash, - }); - - new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupCapacities", { - value: - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.toString(), - description: "PostProcessDeployedRuleGroupCapacities", - exportName: - "PostProcessDeployedRuleGroupCapacities" + - props.config.General.DeployHash, - }); - - new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupIdentifier", { - value: - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.toString(), - description: "PostProcessDeployedRuleGroupIdentifier", - exportName: - "PostProcessDeployedRuleGroupIdentifier" + - props.config.General.DeployHash, - }); - } else { - const threshold = 1000; - const rulesets: any[] = []; - const indexes: number[] = []; - const rulegroupcapacities = []; - while ( - indexes.length < props.runtimeProperties.PostProcessRuleCapacities.length - ) { - let tracker = 0; - const ruleset: any[] = []; - props.runtimeProperties.PostProcessRuleCapacities.map((v, i) => { - 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); + console.log(" ๐Ÿ’ฌ New Name: " + name); } - - console.log( - ` ๐Ÿ–– Split Rules into ${rulesets.length.toString()} RuleGroups:\n` - ); - let count = 0; - let rulegroupidentifier = ""; - let name = ""; - while (count < rulesets.length) { + if (processRuntimeProps.DeployedRuleGroupIdentifier[count]) { if ( - typeof props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[ + processRuntimeProps.DeployedRuleGroupIdentifier[ count - ] !== "undefined" + ] === + "R" + count.toString() ) { - if ( - rulegroupcapacities[count] === - props.runtimeProperties.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.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[ - count - ] + - " !" - ); - console.log( - "\n ๐ŸŸฅ Old Capacity: [" + - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[ - count - ] + - "]\n ๐ŸŸฉ New Capacity: [" + - rulegroupcapacities[count] + - "]" - ); - if ( - typeof props.runtimeProperties - .PostProcessDeployedRuleGroupCapacities[count] !== - "undefined" - ) { - if ( - props.runtimeProperties.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.runtimeProperties - .PostProcessDeployedRuleGroupIdentifier[count] !== undefined - ) { - if ( - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[ - count - ] === - "R" + count.toString() - ) { - rulegroupidentifier = "postG" + count.toString(); - } else { - rulegroupidentifier = "postR" + count.toString(); - } - console.log( - " ๐Ÿ“‡ New Identifier: " + rulegroupidentifier + "\n" - ); - } - } + rulegroupidentifier = type + "G" + count.toString(); } 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: toAwsCamel( - props.config.WebAcl.PostProcess.CustomRules[statementindex] - .Action - ), - statement: toAwsCamel( - 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: toAwsCamel( - props.config.WebAcl.PostProcess.CustomRules[statementindex] - .CaptchaConfig - ), - ruleLabels: toAwsCamel( - props.config.WebAcl.PostProcess.CustomRules[statementindex] - .RuleLabels - ), - }; - } else { - CfnRuleProperty = { - name: rulename, - priority: rulegroupcounter, - action: toAwsCamel( - props.config.WebAcl.PostProcess.CustomRules[statementindex] - .Action - ), - statement: toAwsCamel( - 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: toAwsCamel( - 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++; + rulegroupidentifier = type + "R" + count.toString(); } - 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() + - "]" + " ๐Ÿ“‡ New Identifier: " + rulegroupidentifier + "\n" ); - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities[count] = - rulegroupcapacities[count]; - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier[count] = - rulegroupidentifier; - props.runtimeProperties.PostProcessDeployedRuleGroupNames[count] = name; - count++; } - const lenght = rulesets.length; - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.splice( - lenght - ); - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.splice( - lenght - ); - props.runtimeProperties.PostProcessDeployedRuleGroupNames.splice(lenght); - - new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupNames", { - value: - props.runtimeProperties.PostProcessDeployedRuleGroupNames.toString(), - description: "PostProcessDeployedRuleGroupNames", - exportName: - "PostProcessDeployedRuleGroupNames" + - props.config.General.DeployHash, - }); - - new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupIdentifier", { - value: - props.runtimeProperties.PostProcessDeployedRuleGroupIdentifier.toString(), - description: "PostProcessDeployedRuleGroupIdentifier", - exportName: - "PostProcessDeployedRuleGroupIdentifier" + - props.config.General.DeployHash, - }); - - new cdk.CfnOutput(this, "PostProcessDeployedRuleGroupCapacities", { - value: - props.runtimeProperties.PostProcessDeployedRuleGroupCapacities.toString(), - description: "PostProcessDeployedRuleGroupCapacities", - exportName: - "PostProcessDeployedRuleGroupCapacities" + - props.config.General.DeployHash, - }); } - } - const novalue = null; - if (!props.config.WebAcl.PostProcess.ManagedRuleGroups) { - console.log("\nโ„น๏ธ No ManagedRuleGroups defined in PostProcess."); } else { - let mangedrule; - for (mangedrule of props.config.WebAcl.PostProcess.ManagedRuleGroups) { - let ExcludeRules; - let OverrideAction; - if (mangedrule.ExcludeRules) { - ExcludeRules = toAwsCamel(mangedrule.ExcludeRules); - OverrideAction = mangedrule.OverrideAction; - } else { - ExcludeRules = []; - OverrideAction = { type: "NONE" }; - } - if (mangedrule.Version === "") { - postProcessRuleGroups.push({ - managedRuleGroupIdentifier: { - vendorName: mangedrule.Vendor, - managedRuleGroupName: mangedrule.Name, - version: novalue, - }, - overrideAction: OverrideAction, - ruleGroupArn: novalue, - excludeRules: ExcludeRules, - ruleGroupType: "ManagedRuleGroup", - }); - } else { - postProcessRuleGroups.push({ - managedRuleGroupIdentifier: { - vendorName: mangedrule.Vendor, - managedRuleGroupName: mangedrule.Name, - version: mangedrule.Version, - }, - overrideAction: OverrideAction, - ruleGroupArn: novalue, - excludeRules: ExcludeRules, - ruleGroupType: "ManagedRuleGroup", - }); - } - } + rulegroupidentifier = type + "R" + count.toString(); + name = + webaclName + + "-" + + stage + + "-" + + count.toString() + + "-" + + deployHash; } - if (!props.config.WebAcl.PreProcess.ManagedRuleGroups) { - 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 = toAwsCamel(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", - }); - } + const CfnRuleProperties = []; + let rulegroupcounter = 0; + while (rulegroupcounter < rulesets[count].length) { + const statementindex = rulesets[count][rulegroupcounter]; + let rulename = ""; + if ( + ruleGroupSet[statementindex] + .Name !== undefined + ) { + const Temp_Hash = Date.now().toString(36); + rulename = + ruleGroupSet[statementindex] + .Name + + "-" + + Temp_Hash; + } else { + rulename = + webaclName + + "-" + + stage + + "-"+type.toLocaleLowerCase()+"-" + + rulegroupcounter.toString() + + "-" + + deployHash; + } + let CfnRuleProperty; + if ( + "Captcha" in + ruleGroupSet[statementindex] + .Action + ) { + CfnRuleProperty = { + name: rulename, + priority: rulegroupcounter, + action: toAwsCamel( + ruleGroupSet[statementindex] + .Action + ), + statement: toAwsCamel( + ruleGroupSet[statementindex] + .Statement + ), + visibilityConfig: { + sampledRequestsEnabled: + ruleGroupSet[statementindex] + .VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: + ruleGroupSet[statementindex] + .VisibilityConfig.CloudWatchMetricsEnabled, + metricName: rulename + "-metric", + }, + captchaConfig: toAwsCamel( + ruleGroupSet[statementindex] + .CaptchaConfig + ), + ruleLabels: toAwsCamel( + ruleGroupSet[statementindex] + .RuleLabels + ), + }; + } else { + CfnRuleProperty = { + name: rulename, + priority: rulegroupcounter, + action: toAwsCamel( + ruleGroupSet[statementindex] + .Action + ), + statement: toAwsCamel( + ruleGroupSet[statementindex] + .Statement + ), + visibilityConfig: { + sampledRequestsEnabled: + ruleGroupSet[statementindex] + .VisibilityConfig.SampledRequestsEnabled, + cloudWatchMetricsEnabled: + ruleGroupSet[statementindex] + .VisibilityConfig.CloudWatchMetricsEnabled, + metricName: rulename + "-metric", + }, + ruleLabels: toAwsCamel( + ruleGroupSet[statementindex] + .RuleLabels + ), + }; + } + let CfnRuleProperti: wafv2.CfnRuleGroup.RuleProperty; + if ( + ruleGroupSet[statementindex] + .RuleLabels + ) { + CfnRuleProperti = CfnRuleProperty; + } else { + const { ruleLabels, ...CfnRulePropertii } = CfnRuleProperty; + CfnRuleProperti = CfnRulePropertii; } + CfnRuleProperties.push(CfnRuleProperti); + rulegroupcounter++; } - const securityservicepolicydata = { - type: "WAFV2", - defaultAction: { - type: "ALLOW", + new wafv2.CfnRuleGroup(scope, rulegroupidentifier, { + capacity: rulegroupcapacities[count], + scope: webAclScope, + rules: CfnRuleProperties, + name: name, + visibilityConfig: { + sampledRequestsEnabled: false, + cloudWatchMetricsEnabled: false, + metricName: name + "-metric", }, - preProcessRuleGroups, - 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) - ), - }, + serviceDataRuleGroup.push({ + ruleGroupType: "RuleGroup", + ruleGroupArn: "${" + rulegroupidentifier + ".Arn}", + overrideAction: { type: "NONE" }, }); + console.log( + " โžก๏ธ Creating " + + rulegroupidentifier + + " with calculated capacity: [" + + rulegroupcapacities[count].toString() + + "]" + ); + processRuntimeProps.DeployedRuleGroupCapacities[count] = + rulegroupcapacities[count]; + processRuntimeProps.DeployedRuleGroupIdentifier[count] = + rulegroupidentifier; + processRuntimeProps.DeployedRuleGroupNames[count] = name; + count++; } + const lenght = rulesets.length; + processRuntimeProps.DeployedRuleGroupCapacities.splice( + lenght + ); + processRuntimeProps.DeployedRuleGroupIdentifier.splice( + lenght + ); + processRuntimeProps.DeployedRuleGroupNames.splice(lenght); + + new cdk.CfnOutput(scope, "PreProcessDeployedRuleGroupNames", { + value: + processRuntimeProps.DeployedRuleGroupNames.toString(), + description: "PreProcessDeployedRuleGroupNames", + exportName: + "PreProcessDeployedRuleGroupNames" + + deployHash, + }); - const options = { flag: "w", force: true }; - (async () => { - try { - 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); - } - })(); + new cdk.CfnOutput(scope, "PreProcessDeployedRuleGroupCapacities", { + value: + processRuntimeProps.DeployedRuleGroupCapacities.toString(), + description: "PreProcessDeployedRuleGroupCapacities", + exportName: + "PreProcessDeployedRuleGroupCapacities" + + deployHash, + }); + + new cdk.CfnOutput(scope, "PreProcessDeployedRuleGroupIdentifier", { + value: + processRuntimeProps.DeployedRuleGroupIdentifier.toString(), + description: "PreProcessDeployedRuleGroupIdentifier", + exportName: + "PreProcessDeployedRuleGroupIdentifier" + + deployHash, + }); } + return serviceDataRuleGroup; } \ No newline at end of file diff --git a/lib/tools/helpers.ts b/lib/tools/helpers.ts index 381f88c2..bb3fa276 100644 --- a/lib/tools/helpers.ts +++ b/lib/tools/helpers.ts @@ -2,7 +2,7 @@ import { WAFV2Client, CheckCapacityCommand, CheckCapacityCommandInput, DescribeM 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"; -import { Rule } from "../types/config"; +import { Rule } from "../types/fms"; import * as lodash from "lodash"; import { RuntimeProperties } from "../types/runtimeprops"; import { Config } from "../types/config"; @@ -160,42 +160,42 @@ export async function setOutputsFromStack(deploymentRegion: string, runtimeprops for(const output of responsestack.Stacks?.[0].Outputs){ if(output.OutputKey === "DeployedRuleGroupNames") { - runtimeprops.PreProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; + runtimeprops.PreProcess.DeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; } else if(output.OutputKey === "DeployedRuleGroupIdentifier") { - runtimeprops.PreProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; + runtimeprops.PreProcess.DeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; } else if(output.OutputKey === "DeployedRuleGroupCapacities") { const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; - runtimeprops.PreProcessDeployedRuleGroupCapacities = arrayOfNumbers; + runtimeprops.PreProcess.DeployedRuleGroupCapacities = arrayOfNumbers; } if(output.OutputKey === "PreProcessDeployedRuleGroupNames") { - runtimeprops.PreProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; + runtimeprops.PreProcess.DeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; } else if(output.OutputKey === "PreProcessDeployedRuleGroupIdentifier") { - runtimeprops.PreProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; + runtimeprops.PreProcess.DeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; } else if(output.OutputKey === "PreProcessDeployedRuleGroupCapacities") { const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; - runtimeprops.PreProcessDeployedRuleGroupCapacities = arrayOfNumbers; + runtimeprops.PreProcess.DeployedRuleGroupCapacities = arrayOfNumbers; } if(output.OutputKey === "PostProcessDeployedRuleGroupNames") { - runtimeprops.PostProcessDeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; + runtimeprops.PostProcess.DeployedRuleGroupNames = output.OutputValue?.split(",",output.OutputValue?.length) || []; } else if(output.OutputKey === "PostProcessDeployedRuleGroupIdentifier") { - runtimeprops.PostProcessDeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; + runtimeprops.PostProcess.DeployedRuleGroupIdentifier = output.OutputValue?.split(",",output.OutputValue?.length) || []; } else if(output.OutputKey === "PostProcessDeployedRuleGroupCapacities") { const arrayOfNumbers = output.OutputValue?.split(",",output.OutputValue?.length).map(Number) || []; - runtimeprops.PostProcessDeployedRuleGroupCapacities = arrayOfNumbers; + runtimeprops.PostProcess.DeployedRuleGroupCapacities = arrayOfNumbers; } } } @@ -242,7 +242,7 @@ async function calculateCapacities( config.WebAcl.Scope, rules ); - runtimeProperties.PreProcessRuleCapacities.push(capacity); + runtimeProperties.PreProcess.RuleCapacities.push(capacity); } else { const rule_calculated_capacity_json = []; const { CloudWatchMetricsEnabled, SampledRequestsEnabled } = @@ -263,11 +263,11 @@ async function calculateCapacities( config.WebAcl.Scope, rule_calculated_capacity_json ); - runtimeProperties.PreProcessRuleCapacities.push(capacity); + runtimeProperties.PreProcess.RuleCapacities.push(capacity); } count++; } - runtimeProperties.PreProcessCapacity = runtimeProperties.PreProcessRuleCapacities.reduce( + runtimeProperties.PreProcess.Capacity = runtimeProperties.PreProcess.RuleCapacities.reduce( function (a, b) { return a + b; }, @@ -309,10 +309,10 @@ async function calculateCapacities( config.WebAcl.Scope, rule_calculated_capacity_json ); - runtimeProperties.PostProcessRuleCapacities.push(capacity); + runtimeProperties.PostProcess.RuleCapacities.push(capacity); count++; } - PostProcessCapacity = runtimeProperties.PostProcessRuleCapacities.reduce( + PostProcessCapacity = runtimeProperties.PostProcess.RuleCapacities.reduce( function (a, b) { return a + b; }, @@ -366,7 +366,7 @@ async function calculateCapacities( runtimeProperties.ManagedRuleCapacity += capacity; } } - runtimeProperties.PostProcessCapacity = PostProcessCapacity; + runtimeProperties.PostProcess.Capacity = PostProcessCapacity; } /** @@ -399,8 +399,8 @@ export async function isPolicyQuotaReached(deploymentRegion: string): Promise { await calculateCapacities(config, deploymentRegion, runtimeProps); - const custom_capacity = runtimeProps.PreProcessCapacity + runtimeProps.PostProcessCapacity; - const total_wcu = runtimeProps.PreProcessCapacity + runtimeProps.PostProcessCapacity + runtimeProps.ManagedRuleCapacity; + const custom_capacity = runtimeProps.PreProcess.Capacity + runtimeProps.PostProcess.Capacity; + const total_wcu = runtimeProps.PreProcess.Capacity + runtimeProps.PostProcess.Capacity + runtimeProps.ManagedRuleCapacity; const quote_wcu = await getFmsQuota(deploymentRegion, WCU_QUOTA_CODE); const wcuLimitReached = (total_wcu > Number(quote_wcu)); if (wcuLimitReached) { @@ -411,7 +411,7 @@ export async function isWcuQuotaReached(deploymentRegion: string, runtimeProps: else { console.log("\n๐Ÿ”Ž Capacity Check result: ๐ŸŸข \n"); console.log(" ๐Ÿ’ก Account WAF-WCU Quota: " +Number(quote_wcu).toString()); - console.log(" ๐Ÿงฎ Calculated Custom Rule Capacity is: [" + custom_capacity + "] (๐Ÿฅ‡[" + runtimeProps.PreProcessCapacity + "] + ๐Ÿฅˆ[" + runtimeProps.PostProcessCapacity + "]) \n โž• ManagedRulesCapacity: ["+ runtimeProps.ManagedRuleCapacity +"] \n ๏ผ Total Waf Capacity: " + total_wcu.toString() + "\n"); + console.log(" ๐Ÿงฎ Calculated Custom Rule Capacity is: [" + custom_capacity + "] (๐Ÿฅ‡[" + runtimeProps.PreProcess.Capacity + "] + ๐Ÿฅˆ[" + runtimeProps.PostProcess.Capacity + "]) \n โž• ManagedRulesCapacity: ["+ runtimeProps.ManagedRuleCapacity +"] \n ๏ผ Total Waf Capacity: " + total_wcu.toString() + "\n"); } return wcuLimitReached; } @@ -423,16 +423,20 @@ export async function isWcuQuotaReached(deploymentRegion: string, runtimeProps: export function initRuntimeProperties() : RuntimeProperties { return { ManagedRuleCapacity: 0, - PreProcessCapacity: 0, - PostProcessCapacity: 0, - PreProcessDeployedRuleGroupCapacities: [], - PreProcessRuleCapacities: [], - PreProcessDeployedRuleGroupNames: [], - PreProcessDeployedRuleGroupIdentifier: [], - PostProcessDeployedRuleGroupCapacities: [], - PostProcessRuleCapacities: [], - PostProcessDeployedRuleGroupNames: [], - PostProcessDeployedRuleGroupIdentifier: [], + PostProcess: { + Capacity: 0, + DeployedRuleGroupCapacities: [], + DeployedRuleGroupIdentifier: [], + DeployedRuleGroupNames: [], + RuleCapacities: [] + }, + PreProcess: { + Capacity: 0, + DeployedRuleGroupCapacities: [], + DeployedRuleGroupIdentifier: [], + DeployedRuleGroupNames: [], + RuleCapacities: [] + }, }; } diff --git a/lib/types/config.ts b/lib/types/config.ts index d18529dc..c64b2459 100644 --- a/lib/types/config.ts +++ b/lib/types/config.ts @@ -1,3 +1,4 @@ +import { Rule, ManagedRuleGroup } from "./fms"; export interface Config { readonly General: { readonly Prefix: string, @@ -12,56 +13,12 @@ export interface Config { readonly Name: string, readonly Scope: "CLOUDFRONT" | "REGIONAL", readonly Type: string, - readonly PreProcess: RouleGroupSet, - readonly PostProcess: RouleGroupSet + readonly PreProcess: RuleGroupSet, + readonly PostProcess: RuleGroupSet }, } -interface RouleGroupSet { +export interface RuleGroupSet { CustomRules?: Rule[], ManagedRuleGroups?: ManagedRuleGroup[]; -} - -interface ManagedRuleGroup { - Vendor: string, - Name: string, - Version: string, - Capacity: number, - ExcludeRules?: NameObject[], - OverrideAction?: { - type: "COUNT" | "NONE" - } -} -export interface Rule { - Name?: string, - Statement: any, - Action: Action, - VisibilityConfig: { - SampledRequestsEnabled: boolean, - CloudWatchMetricsEnabled: boolean, - MetricName?: string - }, - CaptchaConfig?: { - ImmunityTimeProperty?: { - ImmunityTime: number - } - }, - RuleLabels?: NameObject[] -} - -type NameObject = { - Name: string -} - -type Action = | { - Block: Record -} -| { - Allow: Record -} -| { - Count: Record -} -| { - Captcha: Record } \ No newline at end of file diff --git a/lib/types/fms.ts b/lib/types/fms.ts new file mode 100644 index 00000000..de3c5629 --- /dev/null +++ b/lib/types/fms.ts @@ -0,0 +1,79 @@ +export interface ManagedRuleGroup { + Vendor: string, + Name: string, + Version: string, + Capacity: number, + ExcludeRules?: NameObject[], + OverrideAction?: { + type: "COUNT" | "NONE" + } +} + +export interface Rule { + Name?: string, + Statement: any, + Action: Action, + VisibilityConfig: { + SampledRequestsEnabled: boolean, + CloudWatchMetricsEnabled: boolean, + MetricName?: string + }, + CaptchaConfig?: { + ImmunityTimeProperty?: { + ImmunityTime: number + } + }, + RuleLabels?: NameObject[] +} + +export interface ManagedServiceData { + type: string, + defaultAction: { + type: "ALLOW" | "DENY" | "COUNT" | "NONE" + }, + preProcessRuleGroups: any, + postProcessRuleGroups: any, + overrideCustomerWebACLAssociation: boolean, + loggingConfiguration: { + logDestinationConfigs: string[] + } +} + +type NameObject = { + Name: string +} + +export interface ServiceDataManagedRuleGroup extends ServiceDataAbstactRuleGroup { + managedRuleGroupIdentifier: { + vendorName: string, + managedRuleGroupName: string, + version: string | null, + }, + excludeRules: any, + ruleGroupType: "ManagedRuleGroup", +} + +export interface ServiceDataRuleGroup extends ServiceDataAbstactRuleGroup { + ruleGroupType: "RuleGroup" +} + +interface ServiceDataAbstactRuleGroup { + overrideAction: { + type: "ALLOW" | "DENY" | "NONE" | "COUNT" + }, + ruleGroupArn: string | null, + ruleGroupType: string +} + +type Action = | { + Block: Record +} +| { + Allow: Record +} +| { + Count: Record +} +| { + Captcha: Record +} \ No newline at end of file diff --git a/lib/types/runtimeprops.ts b/lib/types/runtimeprops.ts index 5b663669..f6ac8b99 100644 --- a/lib/types/runtimeprops.ts +++ b/lib/types/runtimeprops.ts @@ -1,13 +1,13 @@ export interface RuntimeProperties { - PreProcessCapacity: number, - PostProcessCapacity: number, - ManagedRuleCapacity: number, - PreProcessRuleCapacities: number[], - PostProcessRuleCapacities: number[], - PreProcessDeployedRuleGroupCapacities: number[], - PreProcessDeployedRuleGroupNames: string[], - PreProcessDeployedRuleGroupIdentifier: string[], - PostProcessDeployedRuleGroupCapacities: number[], - PostProcessDeployedRuleGroupNames: string[], - PostProcessDeployedRuleGroupIdentifier: string[], + PreProcess: ProcessProperties, + PostProcess: ProcessProperties, + ManagedRuleCapacity: number +} + +export interface ProcessProperties { + Capacity: number, + RuleCapacities: number[], + DeployedRuleGroupCapacities: number[], + DeployedRuleGroupNames: string[], + DeployedRuleGroupIdentifier: string[] } \ No newline at end of file From 54aa2f6f1573629e8dc3e876cd16e4a8a7d1ea96 Mon Sep 17 00:00:00 2001 From: Marcell Jobs <31279340+kirnberger1980@users.noreply.github.com> Date: Mon, 28 Feb 2022 16:40:25 +0100 Subject: [PATCH 4/4] Change Log for version 2.1.0 --- CHANGELOG.md | 16 ++++++++++++++++ package.json | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65778d27..7fbcb790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ ## Released +## 2.1.0 + +### Added + +- Added Linting with typescript-eslint +- Added .gitignore and .npmignore file +- Added 2 functions for building service data (managed & custom rules) to remove redundant code + +### Changed + +- Refactoring bin file: outsource capacity checks & other functions to helpers.ts +- Transform capacity.json to Typescript Type Rule +- Start refactoring lib file: get rid of redundant code and use JS shortcuts +- Extend types of the Config interface +- Restructuring runtime properties: introduce separate layer for PreProcess and PostProcess +- New types for Firewall Manager API and CDK mapping ## 2.0.0 ### Added diff --git a/package.json b/package.json index 90bdf7e1..9bf422fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plattform-wafv2-cdk-automation", - "version": "2.0.0", + "version": "2.1.0", "bin": { "plattform-wafv2-cdk-automation": "bin/plattform-wafv2-cdk-automation.js" },