From b1f472bcd8e18bafc9b8d88f2d570351726ada3a Mon Sep 17 00:00:00 2001 From: Daniel Van Der Ploeg Date: Wed, 15 Nov 2023 14:33:20 +1030 Subject: [PATCH 1/6] feat: create some default waf rules --- packages/graphql-mesh-server/lib/fargate.ts | 63 +++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/packages/graphql-mesh-server/lib/fargate.ts b/packages/graphql-mesh-server/lib/fargate.ts index 0fef4854..76fd5986 100644 --- a/packages/graphql-mesh-server/lib/fargate.ts +++ b/packages/graphql-mesh-server/lib/fargate.ts @@ -11,10 +11,12 @@ import * as auto_scaling from "aws-cdk-lib/aws-autoscaling"; import { Port, SecurityGroup, IVpc, Vpc } from "aws-cdk-lib/aws-ec2"; import { RedisService } from "./redis-construct"; import { + AWSManagedRule, ManagedRule, Scope, WebApplicationFirewall, } from "./web-application-firewall"; +import { CfnIPSet, CfnWebACL } from "aws-cdk-lib/aws-wafv2"; export interface MeshServiceProps { /** @@ -56,6 +58,23 @@ export interface MeshServiceProps { * SSM values to pass through to the container as secrets */ secrets?: { [key: string]: ssm.IStringParameter | ssm.IStringListParameter }; + /** + * List of IP addresses to block (currently only support IPv4) + */ + blockedIps?: string[]; + /** + * List of AWS Managed rules to add to the WAF + */ + wafManagedRules?: AWSManagedRule[]; + /** + * List of custom rules + */ + wafRules?: CfnWebACL.RuleProperty[]; + /** + * The limit on requests per 5-minute period + * If provided, rate limiting will be enabled + */ + rateLimit?: number; } export class MeshService extends Construct { @@ -174,6 +193,48 @@ export class MeshService extends Construct { this.service = fargateService.service; + const blockedIpList = new CfnIPSet(this, "BlockedIpList", { + addresses: props.blockedIps || [], + ipAddressVersion: "IPV4", + scope: "CLOUDFRONT", + description: "List of IPs blocked by WAF", + }); + + const defaultRules: CfnWebACL.RuleProperty[] = [ + { + name: "IPBlockList", + priority: 2, + statement: { + ipSetReferenceStatement: { + arn: blockedIpList.attrArn, + }, + }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: "IPBlockList", + sampledRequestsEnabled: true, + }, + }, + ]; + + if (props.rateLimit) { + defaultRules.push({ + name: "RateLimit", + priority: 3, + statement: { + rateBasedStatement: { + aggregateKeyType: 'FORWARDED_IP', + limit: props.rateLimit, + }, + }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: "RateLimit", + sampledRequestsEnabled: true, + }, + }); + } + this.firewall = new WebApplicationFirewall(this, "waf", { scope: Scope.REGIONAL, visibilityConfig: { @@ -193,7 +254,9 @@ export class MeshService extends Construct { { name: ManagedRule.KNOWN_BAD_INPUTS_RULE_SET, }, + ...(props.wafManagedRules || []), ], + rules: [...defaultRules, ...(props.wafRules || [])], }); this.firewall.addAssociation( From cd246b8955b49bed57c6995463e2577145a3cfdc Mon Sep 17 00:00:00 2001 From: Daniel Van Der Ploeg Date: Wed, 15 Nov 2023 14:35:44 +1030 Subject: [PATCH 2/6] feat: pass props between constructs --- .../lib/graphql-mesh-server.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts index 2d95a8ed..3ec7c159 100644 --- a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts +++ b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts @@ -7,6 +7,8 @@ import { Repository } from "aws-cdk-lib/aws-ecr"; import { FargateService } from "aws-cdk-lib/aws-ecs"; import { CfnCacheCluster } from "aws-cdk-lib/aws-elasticache"; import * as ssm from "aws-cdk-lib/aws-ssm"; +import { AWSManagedRule } from "./web-application-firewall"; +import { CfnWebACL } from "aws-cdk-lib/aws-wafv2"; export type MeshHostingProps = { /** @@ -60,6 +62,23 @@ export type MeshHostingProps = { * ARN of the SNS Topic to send deployment notifications to */ notificationArn?: string; + /** + * List of IP addresses to block (currently only support IPv4) + */ + blockedIps?: string[]; + /** + * List of AWS Managed rules to add to the WAF + */ + wafManagedRules?: AWSManagedRule[]; + /** + * List of custom rules + */ + wafRules?: CfnWebACL.RuleProperty[]; + /** + * The limit on requests per 5-minute period + * If provided, rate limiting will be enabled + */ + rateLimit?: number; }; export class MeshHosting extends Construct { From d519186ebd71978abcedfb5c060ab0d0ff2237c6 Mon Sep 17 00:00:00 2001 From: Daniel Van Der Ploeg Date: Thu, 16 Nov 2023 11:13:20 +1030 Subject: [PATCH 3/6] feat: fix rate limit rule --- packages/graphql-mesh-server/lib/fargate.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/graphql-mesh-server/lib/fargate.ts b/packages/graphql-mesh-server/lib/fargate.ts index 76fd5986..164afd74 100644 --- a/packages/graphql-mesh-server/lib/fargate.ts +++ b/packages/graphql-mesh-server/lib/fargate.ts @@ -223,8 +223,12 @@ export class MeshService extends Construct { priority: 3, statement: { rateBasedStatement: { - aggregateKeyType: 'FORWARDED_IP', + aggregateKeyType: "FORWARDED_IP", limit: props.rateLimit, + forwardedIpConfig: { + fallbackBehavior: "MATCH", + headerName: "X-Forwarded-For", + }, }, }, visibilityConfig: { @@ -232,6 +236,9 @@ export class MeshService extends Construct { metricName: "RateLimit", sampledRequestsEnabled: true, }, + action: { + block: {}, + }, }); } From 658cae8dd5d004d41082c0bb4e71dab3f3e33e66 Mon Sep 17 00:00:00 2001 From: Daniel Van Der Ploeg Date: Thu, 16 Nov 2023 11:19:29 +1030 Subject: [PATCH 4/6] feat: remove ip block and pass priority var --- packages/graphql-mesh-server/lib/fargate.ts | 35 ++++--------------- .../lib/graphql-mesh-server.ts | 9 ++--- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/packages/graphql-mesh-server/lib/fargate.ts b/packages/graphql-mesh-server/lib/fargate.ts index 164afd74..666011d2 100644 --- a/packages/graphql-mesh-server/lib/fargate.ts +++ b/packages/graphql-mesh-server/lib/fargate.ts @@ -58,10 +58,6 @@ export interface MeshServiceProps { * SSM values to pass through to the container as secrets */ secrets?: { [key: string]: ssm.IStringParameter | ssm.IStringListParameter }; - /** - * List of IP addresses to block (currently only support IPv4) - */ - blockedIps?: string[]; /** * List of AWS Managed rules to add to the WAF */ @@ -75,6 +71,11 @@ export interface MeshServiceProps { * If provided, rate limiting will be enabled */ rateLimit?: number; + /** + * The waf rule priority. Only used when a rateLimit value is provided. + * Defaults to 10 + */ + rateLimitPriority?: number; } export class MeshService extends Construct { @@ -193,34 +194,12 @@ export class MeshService extends Construct { this.service = fargateService.service; - const blockedIpList = new CfnIPSet(this, "BlockedIpList", { - addresses: props.blockedIps || [], - ipAddressVersion: "IPV4", - scope: "CLOUDFRONT", - description: "List of IPs blocked by WAF", - }); - - const defaultRules: CfnWebACL.RuleProperty[] = [ - { - name: "IPBlockList", - priority: 2, - statement: { - ipSetReferenceStatement: { - arn: blockedIpList.attrArn, - }, - }, - visibilityConfig: { - cloudWatchMetricsEnabled: true, - metricName: "IPBlockList", - sampledRequestsEnabled: true, - }, - }, - ]; + const defaultRules: CfnWebACL.RuleProperty[] = []; if (props.rateLimit) { defaultRules.push({ name: "RateLimit", - priority: 3, + priority: 10 || props.rateLimitPriority, statement: { rateBasedStatement: { aggregateKeyType: "FORWARDED_IP", diff --git a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts index 3ec7c159..fa8eaa90 100644 --- a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts +++ b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts @@ -62,10 +62,6 @@ export type MeshHostingProps = { * ARN of the SNS Topic to send deployment notifications to */ notificationArn?: string; - /** - * List of IP addresses to block (currently only support IPv4) - */ - blockedIps?: string[]; /** * List of AWS Managed rules to add to the WAF */ @@ -79,6 +75,11 @@ export type MeshHostingProps = { * If provided, rate limiting will be enabled */ rateLimit?: number; + /** + * The waf rule priority. Only used when a rateLimit value is provided. + * Defaults to 10 + */ + rateLimitPriority?: number; }; export class MeshHosting extends Construct { From cdb03872d757fbdb9850676b4a3f9508f6f52e57 Mon Sep 17 00:00:00 2001 From: Daniel Van Der Ploeg Date: Thu, 16 Nov 2023 11:49:44 +1030 Subject: [PATCH 5/6] feat: add ip block list --- packages/graphql-mesh-server/lib/fargate.ts | 38 ++++++++++++++++++- .../lib/graphql-mesh-server.ts | 9 +++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/packages/graphql-mesh-server/lib/fargate.ts b/packages/graphql-mesh-server/lib/fargate.ts index 666011d2..8d2c324a 100644 --- a/packages/graphql-mesh-server/lib/fargate.ts +++ b/packages/graphql-mesh-server/lib/fargate.ts @@ -58,6 +58,15 @@ export interface MeshServiceProps { * SSM values to pass through to the container as secrets */ secrets?: { [key: string]: ssm.IStringParameter | ssm.IStringListParameter }; + /** + * List of IP addresses to block (currently only support IPv4) + */ + blockedIps?: string[]; + /** + * The waf rule priority. + * Defaults to 2 + */ + blockedIpPriority?: number /** * List of AWS Managed rules to add to the WAF */ @@ -73,7 +82,7 @@ export interface MeshServiceProps { rateLimit?: number; /** * The waf rule priority. Only used when a rateLimit value is provided. - * Defaults to 10 + * Defaults to 10 */ rateLimitPriority?: number; } @@ -194,7 +203,32 @@ export class MeshService extends Construct { this.service = fargateService.service; - const defaultRules: CfnWebACL.RuleProperty[] = []; + const blockedIpList = new CfnIPSet(this, "BlockedIpList", { + addresses: props.blockedIps || [], + ipAddressVersion: "IPV4", + scope: "REGIONAL", + description: "List of IPs blocked by WAF", + }); + + const defaultRules: CfnWebACL.RuleProperty[] = [ + { + name: "IPBlockList", + priority: 2 || props.blockedIpPriority, + statement: { + ipSetReferenceStatement: { + arn: blockedIpList.attrArn, + }, + }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: "IPBlockList", + sampledRequestsEnabled: true, + }, + action: { + block: {}, + }, + }, + ]; if (props.rateLimit) { defaultRules.push({ diff --git a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts index fa8eaa90..4d56742f 100644 --- a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts +++ b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts @@ -62,6 +62,15 @@ export type MeshHostingProps = { * ARN of the SNS Topic to send deployment notifications to */ notificationArn?: string; + /** + * List of IP addresses to block (currently only support IPv4) + */ + blockedIps?: string[]; + /** + * The waf rule priority. + * Defaults to 2 + */ + blockedIpPriority?: number /** * List of AWS Managed rules to add to the WAF */ From 776f3790006879c8073d92a817251279d36504a7 Mon Sep 17 00:00:00 2001 From: Daniel Van Der Ploeg Date: Thu, 16 Nov 2023 11:54:00 +1030 Subject: [PATCH 6/6] chore: run prettier --- packages/graphql-mesh-server/lib/fargate.ts | 4 ++-- packages/graphql-mesh-server/lib/graphql-mesh-server.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/graphql-mesh-server/lib/fargate.ts b/packages/graphql-mesh-server/lib/fargate.ts index 8d2c324a..25c802c0 100644 --- a/packages/graphql-mesh-server/lib/fargate.ts +++ b/packages/graphql-mesh-server/lib/fargate.ts @@ -64,9 +64,9 @@ export interface MeshServiceProps { blockedIps?: string[]; /** * The waf rule priority. - * Defaults to 2 + * Defaults to 2 */ - blockedIpPriority?: number + blockedIpPriority?: number; /** * List of AWS Managed rules to add to the WAF */ diff --git a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts index 4d56742f..33df718a 100644 --- a/packages/graphql-mesh-server/lib/graphql-mesh-server.ts +++ b/packages/graphql-mesh-server/lib/graphql-mesh-server.ts @@ -68,9 +68,9 @@ export type MeshHostingProps = { blockedIps?: string[]; /** * The waf rule priority. - * Defaults to 2 + * Defaults to 2 */ - blockedIpPriority?: number + blockedIpPriority?: number; /** * List of AWS Managed rules to add to the WAF */ @@ -86,7 +86,7 @@ export type MeshHostingProps = { rateLimit?: number; /** * The waf rule priority. Only used when a rateLimit value is provided. - * Defaults to 10 + * Defaults to 10 */ rateLimitPriority?: number; };