diff --git a/bin/aws-firewall-factory.ts b/bin/aws-firewall-factory.ts index a0ee9505..4e472059 100644 --- a/bin/aws-firewall-factory.ts +++ b/bin/aws-firewall-factory.ts @@ -243,6 +243,7 @@ void (async () => { '\n šŸŖ£ Amazon S3 bucket name must begin with "aws-waf-logs-" followed by at least one \n of the following characters [a-z0-9_.-]\n\n', "\x1b[0m" + "\n\n" ); + process.exit(1); } new WafStack( diff --git a/lib/_prerequisites-stack.ts b/lib/_prerequisites-stack.ts index 41412cf5..b77e2c6a 100644 --- a/lib/_prerequisites-stack.ts +++ b/lib/_prerequisites-stack.ts @@ -613,13 +613,13 @@ export class PrerequisitesStack extends cdk.Stack { "aws-service-role/fms.amazonaws.com/AWSServiceRoleForFMS" ); const snsRoleName = snsRole.roleArn; - const cwService= new iam.ServicePrincipal('cloudwatch.amazonaws.com'); + const cwService = new iam.ServicePrincipal("cloudwatch.amazonaws.com"); const FmsTopic = new sns.Topic(this, "FMS-Notifications-Topic"); FmsTopic.addToResourcePolicy( new iam.PolicyStatement({ actions: ["sns:Publish"], // Add permission for CloudWatchand FMS to publish to the SNS topic - principals: [snsRole,cwService], + principals: [snsRole, cwService], resources: [FmsTopic.topicArn], }) ); @@ -643,20 +643,20 @@ export class PrerequisitesStack extends cdk.Stack { } ); // Create a CloudWatch Alarm for DDoS attack metrics and add the SNS topic as an action - const ddosAlarm = new cloudwatch.Alarm(this, "DdosAlarm", { - metric: new cloudwatch.Metric({ - namespace: "AWS/DDoSProtection", - metricName: "DDoSDetected", - statistic: "Sum", - period: cdk.Duration.minutes(1), - }), - threshold: 0, - evaluationPeriods: 1, - alarmDescription: "Alarm when a DDoS attack is detected", - actionsEnabled: true, - }); - - ddosAlarm.addAlarmAction(new cloudwatch_actions.SnsAction(FmsTopic)); + const ddosAlarm = new cloudwatch.Alarm(this, "DdosAlarm", { + metric: new cloudwatch.Metric({ + namespace: "AWS/DDoSProtection", + metricName: "DDoSDetected", + statistic: "Sum", + period: cdk.Duration.minutes(1), + }), + threshold: 0, + evaluationPeriods: 1, + alarmDescription: "Alarm when a DDoS attack is detected", + actionsEnabled: true, + }); + + ddosAlarm.addAlarmAction(new cloudwatch_actions.SnsAction(FmsTopic)); } if (props.prerequisites.Grafana) { @@ -783,6 +783,5 @@ export class PrerequisitesStack extends cdk.Stack { } ); } - } } diff --git a/lib/_shield-advanced-stack.ts b/lib/_shield-advanced-stack.ts index 8cb04a48..a3864d8d 100644 --- a/lib/_shield-advanced-stack.ts +++ b/lib/_shield-advanced-stack.ts @@ -53,12 +53,13 @@ export class ShieldStack extends cdk.Stack { managedServiceData: cdk.Fn.sub(JSON.stringify(managedServiceData), {}), }, }; + /* eslint-disable @typescript-eslint/no-unused-vars */ const fmspolicy = new fms.CfnPolicy( this, "CfnPolicy", cfnShieldPolicyProps ); // NOSONAR -> SonarQube is identitfying this line as a Major Issue, but it is not. Sonarqube identify the following Error: Either remove this useless object instantiation or use it. - + /* eslint-enable @typescript-eslint/no-unused-vars */ if (props.shieldConfig.General.CreateDashboard === true) { new ShieldDashboard(this, "ShieldDashboardConstruct", { shieldConfig: { diff --git a/lib/tools/helpers/aws-firewall-factory.ts b/lib/tools/helpers/aws-firewall-factory.ts index f6bf71a4..4d8ae924 100644 --- a/lib/tools/helpers/aws-firewall-factory.ts +++ b/lib/tools/helpers/aws-firewall-factory.ts @@ -9,50 +9,74 @@ import { Config, ShieldConfig } from "../../types/config"; */ const FIREWALL_FACTORY_VERSION = packageJsonObject.version; - /** * The function will display info banner and returns deploymentRegion for WAF Stack * @param config configuration object of the values.json * @return deploymentRegion AWS region, e.g. eu-central-1 */ -export const outputInfoBanner = (config?:Config, shieldConfig?: ShieldConfig) => { +export const outputInfoBanner = ( + config?: Config, + shieldConfig?: ShieldConfig +) => { /** * the region into which the stack is deployed */ let deploymentRegion = ""; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - cfonts.say("AWS FIREWALL FACTORY", {font: "block",align: "center",colors: ["#00ecbd"],background: "transparent",letterSpacing: 0,lineHeight: 0,space: true,maxLength: "13",gradient: false,independentGradient: false,transitionGradient: false,env: "node",width:"80%"}); + cfonts.say("AWS FIREWALL FACTORY", { + font: "block", + align: "center", + colors: ["#00ecbd"], + background: "transparent", + letterSpacing: 0, + lineHeight: 0, + space: true, + maxLength: "13", + gradient: false, + independentGradient: false, + transitionGradient: false, + env: "node", + width: "80%", + }); console.log("\n Ā© by globaldatanet"); - console.log("\nšŸ· Version: ","\x1B[1m",FIREWALL_FACTORY_VERSION,"\x1b[0m"); - if(shieldConfig || config){ + console.log("\nšŸ· Version: ", "\x1B[1m", FIREWALL_FACTORY_VERSION, "\x1b[0m"); + if (shieldConfig || config) { console.log("\nšŸ‘¤ AWS FMS Administrator Account: "); - console.log("\x1b[33m",` ${process.env.CDK_DEFAULT_ACCOUNT}`,"\x1b[0m"); - } - if(shieldConfig){ - if(shieldConfig.resourceType === "AWS::CloudFront::Distribution"){ + console.log( + "\x1b[33m", + ` ${process.env.CDK_DEFAULT_ACCOUNT}`, + "\x1b[0m" + ); + } + if (shieldConfig) { + if (shieldConfig.resourceType === "AWS::CloudFront::Distribution") { deploymentRegion = "us-east-1"; - } - else{ + } else { deploymentRegion = process.env.AWS_REGION || "eu-central-1"; } } - if(config){ - if(process.env.PREREQUISITE === "true"){ + if (config) { + if (process.env.PREREQUISITE === "true") { console.log("šŸŒŽ Deployment region:"); - console.log("\x1b[32m",` ${process.env.AWS_REGION}`,"\x1b[0m \n\n"); - } - else{ - if(config.WebAcl.Scope === "CLOUDFRONT"){ + console.log( + "\x1b[32m", + ` ${process.env.AWS_REGION}`, + "\x1b[0m \n\n" + ); + } else { + if (config.WebAcl.Scope === "CLOUDFRONT") { deploymentRegion = "us-east-1"; - } - else{ + } else { deploymentRegion = process.env.REGION || "eu-central-1"; } console.log("šŸŒŽ CDK deployment region:"); - console.log("\x1b[32m",` ${deploymentRegion}`,"\x1b[0m \n"); + console.log( + "\x1b[32m", + ` ${deploymentRegion}`, + "\x1b[0m \n" + ); } - } - else{ + } else { deploymentRegion = process.env.REGION || "eu-central-1"; } return deploymentRegion; @@ -62,7 +86,7 @@ export const outputInfoBanner = (config?:Config, shieldConfig?: ShieldConfig) => * initialize a runtime properties object * @returns the runtime properties object */ -export function initRuntimeProperties() : RuntimeProperties { +export function initRuntimeProperties(): RuntimeProperties { return { AllAwsRegions: [], GuidanceSummary: [], @@ -90,7 +114,7 @@ export function initRuntimeProperties() : RuntimeProperties { CustomRuleCount: 0, IpReputationListCount: 0, CustomRuleGroupCount: 0, - CustomCaptchaRuleCount: 0 + CustomCaptchaRuleCount: 0, }, PreProcess: { Capacity: 0, @@ -104,7 +128,7 @@ export function initRuntimeProperties() : RuntimeProperties { IpReputationListCount: 0, CustomRuleCount: 0, CustomRuleGroupCount: 0, - CustomCaptchaRuleCount: 0 + CustomCaptchaRuleCount: 0, }, Pricing: { Policy: 0, @@ -116,8 +140,8 @@ export function initRuntimeProperties() : RuntimeProperties { Captcha: 0, AccountTakeoverPrevention: 0, AccountTakeoverPreventionRequest: 0, - Dashboard: 0 - } + Dashboard: 0, + }, }; } @@ -125,9 +149,9 @@ export function initRuntimeProperties() : RuntimeProperties { * The function will check if s3 bucket is Parameter is starting with aws-waf-logs- if Logging Configuration is set to S3 * @param config Config */ -export function wrongLoggingConfiguration(config: Config): boolean{ - if(config.General.LoggingConfiguration === "S3"){ - if(!config.General.S3LoggingBucketName.startsWith("aws-waf-logs-")){ +export function wrongLoggingConfiguration(config: Config): boolean { + if (config.General.LoggingConfiguration === "S3") { + if (!config.General.S3LoggingBucketName.startsWith("aws-waf-logs-")) { return true; } return false; diff --git a/lib/tools/helpers/pricing/calculator.ts b/lib/tools/helpers/pricing/calculator.ts index 894ae237..06f9be94 100644 --- a/lib/tools/helpers/pricing/calculator.ts +++ b/lib/tools/helpers/pricing/calculator.ts @@ -7,26 +7,36 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-for-in-array */ /* eslint-disable @typescript-eslint/no-unsafe-return */ -import { PricingClient, GetProductsCommand, GetProductsCommandInput, FilterType } from "@aws-sdk/client-pricing"; +import { + PricingClient, + GetProductsCommand, + GetProductsCommandInput, + FilterType, +} from "@aws-sdk/client-pricing"; import { RuntimeProperties } from "../../../types/runtimeprops"; import { Config, PriceRegions, ShieldConfig } from "../../../types/config"; -import {CloudWatchClient, ListDashboardsCommand, ListDashboardsCommandInput } from "@aws-sdk/client-cloudwatch"; -import { ShieldClient, GetSubscriptionStateCommand } from "@aws-sdk/client-shield"; - +import { + CloudWatchClient, + ListDashboardsCommand, + ListDashboardsCommandInput, +} from "@aws-sdk/client-cloudwatch"; +import { + ShieldClient, + GetSubscriptionStateCommand, +} from "@aws-sdk/client-shield"; /** * Amazon Web Services Price List Service API Endpoint */ const PRICING_API_ENDPOINT_REGION = "us-east-1"; - /** * Find Values in Object - Needed for aws pricing api * @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){ +function findValues(obj: any, key: string) { return findValuesHelper(obj, key, []); } @@ -37,7 +47,7 @@ function findValues(obj: any, key: string){ * @param list any * @returns list */ -function findValuesHelper(obj:any, key:string, list: any) { +function findValuesHelper(obj: any, key: string, list: any) { if (!obj) return list; if (obj instanceof Array) { for (const i of obj) { @@ -62,24 +72,66 @@ function findValuesHelper(obj:any, key:string, list: any) { * @param runtimeProps runtime properties object, where to store prices * @returns true if prices are update in runtimeprops */ -async function getCurrentWafPrices(deploymentRegion: PriceRegions, runtimeProps: RuntimeProperties, config: Config, awsregion: string): Promise { - console.log(" šŸ”Ž Getting current prices for: ", deploymentRegion,"\n"); - 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); +async function getCurrentWafPrices( + deploymentRegion: PriceRegions, + runtimeProps: RuntimeProperties, + config: Config, + awsregion: string +): Promise { + console.log(" šŸ”Ž Getting current prices for: ", deploymentRegion, "\n"); + 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); - runtimeProps.Pricing.Dashboard = await getDashboardPrice(awsregion,config); + 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; + runtimeProps.Pricing.Dashboard = await getDashboardPrice(awsregion, config); return true; - } - catch{ + } catch { return false; } } @@ -89,33 +141,32 @@ async function getCurrentWafPrices(deploymentRegion: PriceRegions, runtimeProps: * @param deploymentRegion AWS region, e.g. eu-central-1 * @returns price for dashboard */ -async function getDashboardPrice(deploymentRegion: string, config: Config ): Promise { - const client = new CloudWatchClient({region: deploymentRegion}); +async function getDashboardPrice( + deploymentRegion: string, + config: Config +): Promise { + const client = new CloudWatchClient({ region: deploymentRegion }); const input: ListDashboardsCommandInput = {}; const command = new ListDashboardsCommand(input); - const response : any = await client.send(command); + const response: any = await client.send(command); if (!response.DashboardEntries || !response.DashboardEntries[0]) { throw new Error("Cant list Dashboards"); } - if(config.General.CreateDashboard){ + if (config.General.CreateDashboard) { const dashboardcount = response.DashboardEntries.length + 1; - if(dashboardcount > 3){ + if (dashboardcount > 3) { const usd = 3; return usd; - } - else{ + } else { const usd = 0; return usd; } - } - else{ + } else { const usd = 0; return usd; } - } - /** * * @param deploymentRegion AWS region, e.g. eu-central-1 @@ -123,107 +174,172 @@ async function getDashboardPrice(deploymentRegion: string, config: Config ): Pro * @param operation * @returns price for one product */ -export async function getProductPrice(deploymentRegion: PriceRegions, servicecode: string, operation?: string,group?: string, groupDescription?: string): Promise { - const client = new PricingClient({region: PRICING_API_ENDPOINT_REGION}); - const filters: {Type: FilterType, Field: string, Value: string}[] = []; - if(groupDescription){ +export async function getProductPrice( + deploymentRegion: PriceRegions, + servicecode: string, + operation?: string, + group?: string, + groupDescription?: string +): Promise { + const client = new PricingClient({ region: PRICING_API_ENDPOINT_REGION }); + const filters: { Type: FilterType; Field: string; Value: string }[] = []; + if (groupDescription) { filters.push({ Type: FilterType.TERM_MATCH, Field: "groupDescription", - Value: groupDescription}); + Value: groupDescription, + }); } - if(group){ + if (group) { filters.push({ Type: FilterType.TERM_MATCH, Field: "group", - Value: group}); + Value: group, + }); } - if(operation){ + if (operation) { filters.push({ Type: FilterType.TERM_MATCH, Field: "operation", - Value: operation + Value: operation, }); } filters.push({ Type: FilterType.TERM_MATCH, Field: "location", - Value: deploymentRegion + Value: deploymentRegion, }); const input: GetProductsCommandInput = { Filters: filters, - ServiceCode: servicecode + ServiceCode: servicecode, }; const command = new GetProductsCommand(input); - const response : any = await client.send(command); + 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]; - const usd = findValues(JSON.parse(priceList.toJSON()),"USD"); + 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 isWafPriceCalculated(deploymentRegion: PriceRegions,runtimeProps: RuntimeProperties, config: Config, awsregion: string): Promise { +export async function isWafPriceCalculated( + deploymentRegion: PriceRegions, + runtimeProps: RuntimeProperties, + config: Config, + awsregion: string +): Promise { const shieldSubscriptionState = await getShieldSubscriptionState(); console.log("\nšŸ›”ļø Shield Advanced State: " + shieldSubscriptionState); console.log("\nšŸ’° Cost: \n"); await getCurrentWafPrices(deploymentRegion, runtimeProps, config, awsregion); - 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; - - let fixedcost = runtimeProps.Pricing.Policy + runtimeProps.Pricing.WebACL + postprocessfixedcost + preprocessfixedcost + botcontrolfixedcost + atpfixedcost + runtimeProps.Pricing.Dashboard; + 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; + + let fixedcost = + runtimeProps.Pricing.Policy + + runtimeProps.Pricing.WebACL + + postprocessfixedcost + + preprocessfixedcost + + botcontrolfixedcost + + atpfixedcost + + runtimeProps.Pricing.Dashboard; const requestscost = runtimeProps.Pricing.Request; - const totalcost = fixedcost + (requestscost * 5) + (captchacost * 5); + const totalcost = fixedcost + requestscost * 5 + captchacost * 5; if (shieldSubscriptionState && shieldSubscriptionState === "ACTIVE") { - fixedcost = botcontrolfixedcost + atpfixedcost + runtimeProps.Pricing.Dashboard; + fixedcost = + botcontrolfixedcost + atpfixedcost + runtimeProps.Pricing.Dashboard; } console.log(" WAF Rules cost: " + fixedcost + " $ per month"); - console.log(" WAF Requests: " + requestscost.toFixed(2) + " $ pro 1 mio requests"); + console.log( + " WAF Requests: " + requestscost.toFixed(2) + " $ pro 1 mio requests" + ); if (captchacost > 0) { - console.log(" WAF Analysis fee:\n Captcha: " + captchacost + "$ per thousand challenge attempts analyzed"); + console.log( + " WAF Analysis fee:\n Captcha: " + + captchacost + + "$ per thousand challenge attempts analyzed" + ); } else { console.log(" "); } - console.log("\n Total WAF cost (monthly): "+ totalcost + " $ *"); - console.log("\n * This costs are based on the expectation that the WAF gets 5 mio requests per month. "); + console.log("\n Total WAF cost (monthly): " + totalcost + " $ *"); + console.log( + "\n * This costs are based on the expectation that the WAF gets 5 mio requests per month. " + ); if (atpfixedcost !== 0) { - console.log("\n * This costs are based on the expectation that 10.000 login attempts were analyzed. "); + console.log( + "\n * This costs are based on the expectation that 10.000 login attempts were analyzed. " + ); } - console.log("\n ā„¹ The costs are calculated based on the provided information at https://aws.amazon.com/waf/pricing/. "); + console.log( + "\n ā„¹ The costs are calculated based on the provided information at https://aws.amazon.com/waf/pricing/. " + ); if (botcontrolfixedcost !== 0) { - console.log(" The deployed WAF includes BotControl rules this costs an extra fee of " + runtimeProps.Pricing.BotControl + " $ and " + runtimeProps.Pricing.BotControlRequest + "$ pro 1 mio requests (10 mio request Free Tier). \n These costs are already included in the price calculation."); + console.log( + " The deployed WAF includes BotControl rules this costs an extra fee of " + + runtimeProps.Pricing.BotControl + + " $ and " + + runtimeProps.Pricing.BotControlRequest + + "$ pro 1 mio requests (10 mio request Free Tier). \n These costs are already included in the price calculation." + ); } if (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."); + 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." + ); } if (runtimeProps.Pricing.Dashboard !== 0) { - console.log(" The deployed WAF includes CloudWatch Dashboard and you have more than 3 Dashboards (Free tier), so you will need to pay " + runtimeProps.Pricing.Dashboard + "$ for this CloudWatch Dashboard. \n These costs are already included in the price calculation."); + console.log( + " The deployed WAF includes CloudWatch Dashboard and you have more than 3 Dashboards (Free tier), so you will need to pay " + + runtimeProps.Pricing.Dashboard + + "$ for this CloudWatch Dashboard. \n These costs are already included in the price calculation." + ); } if (shieldSubscriptionState === "ACTIVE") { - console.log(" AWS WAF WebACLs or Rules created by Firewall Manager - are Included in AWS Shield Advanced. More information at https://aws.amazon.com/firewall-manager/pricing/."); + console.log( + " AWS WAF WebACLs or Rules created by Firewall Manager - are Included in AWS Shield Advanced. More information at https://aws.amazon.com/firewall-manager/pricing/." + ); } console.log("\n\n"); @@ -231,8 +347,8 @@ export async function isWafPriceCalculated(deploymentRegion: PriceRegions,runtim return pricecalculated; } -async function getShieldSubscriptionState(){ - const client = new ShieldClient({region: PRICING_API_ENDPOINT_REGION}); +async function getShieldSubscriptionState() { + const client = new ShieldClient({ region: PRICING_API_ENDPOINT_REGION }); const input = {}; const command = new GetSubscriptionStateCommand(input); const subscriptionState = (await client.send(command)).SubscriptionState; @@ -244,21 +360,37 @@ async function getShieldSubscriptionState(){ * @param runtimeProps runtime properties object, where to get prices * @returns whether price is successfully calculated or not */ -export async function isShieldPriceCalculated(shieldconfig: ShieldConfig): Promise { +export async function isShieldPriceCalculated( + shieldconfig: ShieldConfig +): Promise { const shieldSubscriptionState = await getShieldSubscriptionState(); console.log("\nšŸ›”ļø Shield Advanced State: " + shieldSubscriptionState); console.log("\nšŸ’° Cost: \n"); - console.log(" šŸ›”ļø Shield Advanced Subscription: \n 3000 $ per month (whole Organization)\n"); - console.log(" āŒ— Data Transfer Out Usage Fees: \n") - - if(shieldconfig.resourceType === "AWS::CloudFront::Distribution" || shieldconfig.resourceType === "AWS::GlobalAccelerator::Accelerator"){ - console.log(" first 100 TB 0.025 $ per GB \n next 400 TB 0.020 $ per GB"); - } - else if(shieldconfig.resourceType === "AWS::ElasticLoadBalancingV2::LoadBalancer" || shieldconfig.resourceType === "AWS::ElasticLoadBalancing::LoadBalancer" || shieldconfig.resourceType === "AWS::EC2::EIP"){ - console.log(" first 100 TB 0.05 $ per GB \n next 400 TB 0.04 $ per GB"); + console.log( + " šŸ›”ļø Shield Advanced Subscription: \n 3000 $ per month (whole Organization)\n" + ); + console.log(" āŒ— Data Transfer Out Usage Fees: \n"); + + if ( + shieldconfig.resourceType === "AWS::CloudFront::Distribution" || + shieldconfig.resourceType === "AWS::GlobalAccelerator::Accelerator" + ) { + console.log( + " first 100 TB 0.025 $ per GB \n next 400 TB 0.020 $ per GB" + ); + } else if ( + shieldconfig.resourceType === "AWS::ElasticLoadBalancingV2::LoadBalancer" || + shieldconfig.resourceType === "AWS::ElasticLoadBalancing::LoadBalancer" || + shieldconfig.resourceType === "AWS::EC2::EIP" + ) { + console.log( + " first 100 TB 0.05 $ per GB \n next 400 TB 0.04 $ per GB" + ); } - console.log("\n ā„¹ The costs are calculated based on the provided information at https://aws.amazon.com/shield/pricing/. "); + console.log( + "\n ā„¹ The costs are calculated based on the provided information at https://aws.amazon.com/shield/pricing/. " + ); return true; -} \ No newline at end of file +}