-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from globaldatanet/feature/pricecalculation
Add PriceCalculation Feature
- Loading branch information
Showing
8 changed files
with
236 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
# Change Log | ||
|
||
## Released | ||
## 2.1.2 | ||
|
||
### Added | ||
|
||
- Price calculation for your WAF | ||
## 2.1.1 | ||
|
||
### Fixed | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import { PricingClient, GetProductsCommand, GetProductsCommandInput } from "@aws-sdk/client-pricing"; | ||
import { RuntimeProperties } from "../types/runtimeprops"; | ||
import { PriceRegions } from "../types/config"; | ||
/** | ||
* Amazon Web Services Price List Service API Endpoint | ||
*/ | ||
const PRICING_API_ENDPOINT_REGION = "us-east-1"; | ||
|
||
|
||
/** | ||
* | ||
* @param obj object where the key is included | ||
* @param key key which includes the needed value | ||
* @returns value from key | ||
*/ | ||
function findValues(obj: any, key: string){ | ||
return findValuesHelper(obj, key, []); | ||
} | ||
|
||
function findValuesHelper(obj:any, key:string, list: any) { | ||
if (!obj) return list; | ||
if (obj instanceof Array) { | ||
for (const i in obj) { | ||
list = list.concat(findValuesHelper(obj[i], key, [])); | ||
} | ||
return list; | ||
} | ||
if (obj[key]) list.push(obj[key]); | ||
|
||
if ((typeof obj === "object") && (obj !== null) ){ | ||
const children = Object.keys(obj); | ||
if (children.length > 0){ | ||
for (let i = 0; i < children.length; i++ ){ | ||
list = list.concat(findValuesHelper(obj[children[i]], key, [])); | ||
} | ||
} | ||
} | ||
return list; | ||
} | ||
|
||
/** | ||
* | ||
* @param deploymentRegion AWS region, e.g. eu-central-1 | ||
* @param runtimeProps runtime properties object, where to store prices | ||
* @returns true if prices are update in runtimeprops | ||
*/ | ||
export async function GetCurrentPrices(deploymentRegion: PriceRegions, runtimeProps: RuntimeProperties): Promise<boolean> { | ||
try{ | ||
runtimeProps.Pricing.Policy = Number(await getProductPrice(deploymentRegion,"AWSFMS","WAFv2")); | ||
runtimeProps.Pricing.Rule = Number(await getProductPrice(deploymentRegion,"awswaf",undefined,"Rule")); | ||
runtimeProps.Pricing.WebACL = Number(await getProductPrice(deploymentRegion,"awswaf",undefined,"Web ACL")); | ||
runtimeProps.Pricing.Request = (await getProductPrice(deploymentRegion,"awswaf",undefined,"Request") * 1000000); | ||
runtimeProps.Pricing.BotControl = Number(await getProductPrice(deploymentRegion,"awswaf",undefined,"AMR Bot Control Entity")); | ||
const BotControlRequest: any = await getProductPrice(deploymentRegion,"awswaf",undefined,undefined,"AMR Bot Control Request Processed"); | ||
runtimeProps.Pricing.BotControlRequest = (BotControlRequest[0] * 1000000); | ||
runtimeProps.Pricing.Captcha = 0.4; | ||
runtimeProps.Pricing.AccountTakeoverPrevention = Number(await getProductPrice(deploymentRegion,"awswaf",undefined,"AMR ATP Entity")); | ||
const AccountTakeoverPreventionRequest: any = await getProductPrice(deploymentRegion,"awswaf",undefined,"AMR ATP Login Attempt"); | ||
runtimeProps.Pricing.AccountTakeoverPreventionRequest = (AccountTakeoverPreventionRequest[0] * 1000); | ||
return true; | ||
} | ||
catch{ | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* @param deploymentRegion AWS region, e.g. eu-central-1 | ||
* @param servicecode The code for the service whose products you want to retrieve. | ||
* @param operation | ||
* @returns price for one product | ||
*/ | ||
async function getProductPrice(deploymentRegion: PriceRegions, servicecode: string, operation?: string,group?: string, groupDescription?: string): Promise<number> { | ||
const client = new PricingClient({region: PRICING_API_ENDPOINT_REGION}); | ||
const Filters: {Type: string, Field: string, Value: string}[] = []; | ||
if(groupDescription){ | ||
Filters.push({ | ||
Type: "TERM_MATCH", | ||
Field: "groupDescription", | ||
Value: groupDescription}); | ||
} | ||
if(group){ | ||
Filters.push({ | ||
Type: "TERM_MATCH", | ||
Field: "group", | ||
Value: group}); | ||
} | ||
if(operation){ | ||
Filters.push({ | ||
Type: "TERM_MATCH", | ||
Field: "operation", | ||
Value: operation | ||
}); | ||
} | ||
Filters.push({ | ||
Type: "TERM_MATCH", | ||
Field: "location", | ||
Value: deploymentRegion | ||
}); | ||
|
||
const input: GetProductsCommandInput = { | ||
Filters, | ||
ServiceCode: servicecode | ||
}; | ||
const command = new GetProductsCommand(input); | ||
const response : any = await client.send(command); | ||
if (!response.PriceList || !response.PriceList[0]) { | ||
throw new Error("Price list does not exist"); | ||
} | ||
const priceList = response.PriceList[0] as any; | ||
const USD = findValues(JSON.parse(priceList.toJSON()),"USD"); | ||
return USD || 0; | ||
} | ||
|
||
|
||
/** | ||
* The function calculated the price of the deployed WAF | ||
* @param runtimeProps runtime properties object, where to get prices | ||
* @returns whether price is successfully calculated or not | ||
*/ | ||
export async function isPriceCalculated(runtimeProps: RuntimeProperties): Promise<string> { | ||
const preprocessfixedcost = (runtimeProps.PreProcess.CustomRuleCount * runtimeProps.Pricing.Rule) + runtimeProps.PreProcess.CustomRuleGroupCount + runtimeProps.PreProcess.ManagedRuleGroupCount; | ||
const postprocessfixedcost = (runtimeProps.PostProcess.CustomRuleCount * runtimeProps.Pricing.Rule) + runtimeProps.PostProcess.CustomRuleGroupCount + runtimeProps.PostProcess.ManagedRuleGroupCount; | ||
const captchacost = (runtimeProps.PostProcess.CustomCaptchaRuleCount + runtimeProps.PreProcess.CustomCaptchaRuleCount) * runtimeProps.Pricing.Captcha; | ||
const botcontrolfixedcost = (runtimeProps.PostProcess.ManagedRuleBotControlCount + runtimeProps.PreProcess.ManagedRuleBotControlCount) * runtimeProps.Pricing.BotControl; | ||
const atpfixedcost = (runtimeProps.PostProcess.ManagedRuleATPCount + runtimeProps.PreProcess.ManagedRuleATPCount) * runtimeProps.Pricing.AccountTakeoverPrevention; | ||
const fixedcost = runtimeProps.Pricing.Policy + runtimeProps.Pricing.WebACL + postprocessfixedcost + preprocessfixedcost + botcontrolfixedcost + atpfixedcost; | ||
const requestscost = runtimeProps.Pricing.Request; | ||
const totalcost = fixedcost + (requestscost * 5) + (captchacost * 5); | ||
console.log("\n💰 Cost: \n"); | ||
console.log(" WAF Rules cost: " + fixedcost + " $ per month"); | ||
console.log(" WAF Requests: "+ requestscost + " $ per 1 mio requests"); | ||
(captchacost > 0) ? console.log(" WAF Analysis fee:\n Captcha: " +captchacost +"$ per thousand challenge attempts analyzed") : " "; | ||
console.log("\n Total WAF cost (monthly): "+ totalcost + " $ *"); | ||
console.log("\n * This costs are based on expectation that the WAF gets 5 mio requests per month. "); | ||
(atpfixedcost !== 0) ? console.log("\n *This costs are based on expectation that 10.000 login attempts where analyzed. ") : ""; | ||
console.log("\n ℹ The costs are calculated based on the provided information at https://aws.amazon.com/waf/pricing/. "); | ||
(botcontrolfixedcost !== 0) ? console.log(" The deployed WAF includes BotControl rules this costs an extra fee of "+runtimeProps.Pricing.BotControl +" $ and " +runtimeProps.Pricing.BotControlRequest +"$ per 1 mio requests (10 mio request Free Tier). \n These costs are already included in the price calculation.") : ""; | ||
(atpfixedcost !== 0) ? console.log(" The deployed WAF includes Account Takeover Prevention rules this costs an extra fee of "+runtimeProps.Pricing.AccountTakeoverPrevention+" $ and " + runtimeProps.Pricing.AccountTakeoverPreventionRequest +" $ per thousand login attempts analyzed (10,000 attempts analyzed Free Tier). \n These costs are already included in the price calculation.") : ""; | ||
const pricecalculated = "True"; | ||
return pricecalculated; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,32 @@ | ||
export interface RuntimeProperties { | ||
PreProcess: ProcessProperties, | ||
PostProcess: ProcessProperties, | ||
ManagedRuleCapacity: number | ||
ManagedRuleCapacity: number, | ||
Pricing: ResourcePrices, | ||
} | ||
export interface ResourcePrices { | ||
Policy: number, | ||
Rule: number, | ||
WebACL: number, | ||
Request: number, | ||
BotControl: number, | ||
BotControlRequest: number, | ||
Captcha: number, | ||
AccountTakeoverPrevention: number, | ||
AccountTakeoverPreventionRequest: number, | ||
} | ||
|
||
export interface ProcessProperties { | ||
Capacity: number, | ||
RuleCapacities: number[], | ||
DeployedRuleGroupCapacities: number[], | ||
DeployedRuleGroupNames: string[], | ||
DeployedRuleGroupIdentifier: string[] | ||
DeployedRuleGroupIdentifier: string[], | ||
ManagedRuleGroupCount: number, | ||
ManagedRuleBotControlCount: number, | ||
ManagedRuleATPCount: number, | ||
CustomRuleCount: number, | ||
CustomRuleGroupCount: number, | ||
CustomCaptchaRuleCount: number | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters