diff --git a/dev/dev.ts b/dev/dev.ts index 9e4e527..5e82be2 100644 --- a/dev/dev.ts +++ b/dev/dev.ts @@ -22,7 +22,9 @@ const descriptionWithTag = (tag?: string) => // bring this out to the top as it is the type of thing we might want to change during dev // to point to other PR branches etc -const DEV_DEPLOYED_IMAGE_TAG = "0.4.4"; +const DEV_DEPLOYED_IMAGE_TAG = "0.4.7"; + +let rulePriorityCounter = 0; /** * Stack for dev @@ -63,6 +65,92 @@ new ElsaDataStack( }, enableAccessPoints: true, }, - databaseName: "elsa_data", + databaseName: "elsa_data_nov_2023", + wafRules: [ + { + name: "LimitRequests100", + priority: rulePriorityCounter++, + action: { + block: {}, + }, + statement: { + rateBasedStatement: { + // given our site is not one where you'd expect high traffic - we set this to + // the minimum, and we will see how that plays out + limit: 100, + aggregateKeyType: "IP", + }, + }, + visibilityConfig: { + sampledRequestsEnabled: true, + cloudWatchMetricsEnabled: true, + metricName: "LimitRequests100", + }, + }, + { + name: "AllowedCountriesOnly", + priority: rulePriorityCounter++, + action: { + block: {}, + }, + statement: { + notStatement: { + statement: { + geoMatchStatement: { + // block traffic if not from below + countryCodes: ["AU"], + }, + }, + }, + }, + visibilityConfig: { + sampledRequestsEnabled: true, + cloudWatchMetricsEnabled: true, + metricName: "AllowedCountriesOnly", + }, + }, + { + name: "AWS-AWSManagedRulesCommonRuleSet", + priority: rulePriorityCounter++, + statement: { + managedRuleGroupStatement: { + name: "AWSManagedRulesCommonRuleSet", + vendorName: "AWS", + // an example of how we might want to exclude rules + // excludedRules: [ + // { + // name: "SizeRestrictions_BODY", + // }, + //], + }, + }, + overrideAction: { + none: {}, + }, + visibilityConfig: { + sampledRequestsEnabled: true, + cloudWatchMetricsEnabled: true, + metricName: "AWS-AWSManagedRulesCommonRuleSet", + }, + }, + { + name: "AWS-AWSManagedRulesAmazonIpReputationList", + priority: rulePriorityCounter++, + statement: { + managedRuleGroupStatement: { + vendorName: "AWS", + name: "AWSManagedRulesAmazonIpReputationList", + }, + }, + overrideAction: { + none: {}, + }, + visibilityConfig: { + sampledRequestsEnabled: true, + cloudWatchMetricsEnabled: true, + metricName: "AWS-AWSManagedRulesAmazonIpReputationList", + }, + }, + ], } ); diff --git a/packages/aws-application/app/elsa-data-application-app-runner-construct.ts b/packages/aws-application/app/elsa-data-application-app-runner-construct.ts index 5166ed6..2ce4998 100644 --- a/packages/aws-application/app/elsa-data-application-app-runner-construct.ts +++ b/packages/aws-application/app/elsa-data-application-app-runner-construct.ts @@ -19,6 +19,7 @@ import { IBucket } from "aws-cdk-lib/aws-s3"; import { ContainerConstruct } from "../construct/container-construct"; import { IHostedZone } from "aws-cdk-lib/aws-route53"; import { ICertificate } from "aws-cdk-lib/aws-certificatemanager"; +import { CfnWebACL, CfnWebACLAssociation } from "aws-cdk-lib/aws-wafv2"; interface Props extends ElsaDataApplicationSettings { readonly vpc: ec2.IVpc; @@ -109,6 +110,26 @@ export class ElsaDataApplicationAppRunnerConstruct extends Construct { vpcConnector: vpcConnector, }); + if (props.wafRules && props.wafRules.length > 0) { + const cfnWebAcl = new CfnWebACL(this, "WebAcl", { + defaultAction: { + allow: {}, + }, + scope: "REGIONAL", + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: "MetricForWebACLCDK", + sampledRequestsEnabled: true, + }, + rules: props.wafRules, + }); + + new CfnWebACLAssociation(this, "WebAclAssociation", { + resourceArn: appService.serviceArn, + webAclArn: cfnWebAcl.attrArn, + }); + } + // register a cloudMapService for the Application in our namespace // chose a sensible default - but allow an alteration in case I guess someone might // want to run two Elsa *in the same infrastructure* diff --git a/packages/aws-application/elsa-data-application-settings.ts b/packages/aws-application/elsa-data-application-settings.ts index 5cd88ae..7da48fa 100644 --- a/packages/aws-application/elsa-data-application-settings.ts +++ b/packages/aws-application/elsa-data-application-settings.ts @@ -1,3 +1,5 @@ +import { CfnWebACL } from "aws-cdk-lib/aws-wafv2"; + /** * The user settable settings for the Elsa Data application service. */ @@ -83,6 +85,12 @@ export interface ElsaDataApplicationSettings { * The cpu assigned to the Elsa Data application container - defaults to something sensible */ readonly cpu?: number; + + /** + * If present and non-empty - tells us to use these rules for establishing a WAF. + * If not present, then no WAF is installed. + */ + readonly wafRules?: CfnWebACL.RuleProperty[]; } export interface ElsaDataApplicationBuildLocal {