Skip to content

Commit

Permalink
Merge pull request #57 from unstubbable/waf
Browse files Browse the repository at this point in the history
Associate an AWS WAF web ACL with the CDN
  • Loading branch information
unstubbable authored Mar 14, 2024
2 parents 1aa5f1d + 2d9b0e0 commit 88c81c1
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 28 deletions.
24 changes: 24 additions & 0 deletions apps/aws-app/cdk/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as cdk from 'aws-cdk-lib';
import {MainStack} from './main-stack.js';
import {WafStack} from './waf-stack.js';

const app = new cdk.App();

const wafStack = new WafStack(app, `mfng-waf`, {
crossRegionReferences: true,
env: {
// For a web ACL with CLOUDFRONT scope, the WAF resources must be created in
// the US East (N. Virginia) Region, us-east-1.
region: `us-east-1`,
},
});

new MainStack(app, `mfng-app`, {
crossRegionReferences: true,
env: {
// Cross stack/region references are only supported for stacks with an
// explicit region defined.
region: process.env.AWS_REGION,
},
webAcl: wafStack.webAcl,
});
56 changes: 30 additions & 26 deletions apps/aws-app/cdk/stack.ts → apps/aws-app/cdk/main-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ import type {Construct} from 'constructs';
const verifyHeader = process.env.AWS_HANDLER_VERIFY_HEADER;
const distDirname = path.join(import.meta.dirname, `../dist/`);

export class Stack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
export interface MainStackProps extends cdk.StackProps {
readonly webAcl: cdk.aws_wafv2.CfnWebACL;
}

export class MainStack extends cdk.Stack {
#webAcl: cdk.aws_wafv2.CfnWebACL;

constructor(scope: Construct, id: string, props: MainStackProps) {
const {webAcl, ...otherProps} = props;
super(scope, id, otherProps);
this.#webAcl = webAcl;

const lambdaFunction = new cdk.aws_lambda_nodejs.NodejsFunction(
this,
Expand All @@ -23,15 +31,11 @@ export class Stack extends cdk.Stack {
},
);

const lambdaFunctionUrl = new cdk.aws_lambda.FunctionUrl(
this,
`function-url`,
{
function: lambdaFunction,
authType: cdk.aws_lambda.FunctionUrlAuthType.NONE,
invokeMode: cdk.aws_lambda.InvokeMode.RESPONSE_STREAM,
},
);
const functionUrl = new cdk.aws_lambda.FunctionUrl(this, `function-url`, {
function: lambdaFunction,
authType: cdk.aws_lambda.FunctionUrlAuthType.NONE,
invokeMode: cdk.aws_lambda.InvokeMode.RESPONSE_STREAM,
});

const bucket = new cdk.aws_s3.Bucket(this, `assets-bucket`, {
bucketName: `mfng-aws-app-assets`,
Expand All @@ -41,14 +45,11 @@ export class Stack extends cdk.Stack {

const distribution = new cdk.aws_cloudfront.Distribution(this, `cdn`, {
defaultBehavior: {
origin: new cdk.aws_cloudfront_origins.FunctionUrlOrigin(
lambdaFunctionUrl,
{
customHeaders: verifyHeader
? {'X-Origin-Verify': verifyHeader}
: undefined,
},
),
origin: new cdk.aws_cloudfront_origins.FunctionUrlOrigin(functionUrl, {
customHeaders: verifyHeader
? {'X-Origin-Verify': verifyHeader}
: undefined,
}),
allowedMethods: cdk.aws_cloudfront.AllowedMethods.ALLOW_ALL,
cachePolicy: new cdk.aws_cloudfront.CachePolicy(this, `cache-policy`, {
enableAcceptEncodingGzip: true,
Expand All @@ -68,6 +69,7 @@ export class Stack extends cdk.Stack {
},
},
priceClass: cdk.aws_cloudfront.PriceClass.PRICE_CLASS_100,
webAclId: this.#webAcl.attrArn,
});

new cdk.aws_s3_deployment.BucketDeployment(this, `assets-deployment`, {
Expand All @@ -82,12 +84,14 @@ export class Stack extends cdk.Stack {
cacheControl: [cdk.aws_s3_deployment.CacheControl.immutable()],
});

new cdk.CfnOutput(this, `cdn-domain-name`, {
value: distribution.domainName,
new cdk.CfnOutput(this, `function-url-output`, {
exportName: `function-url`,
value: functionUrl.url,
});

new cdk.CfnOutput(this, `cdn-url-output`, {
exportName: `cdn-url`,
value: `https://${distribution.domainName}`,
});
}
}

const app = new cdk.App();

new Stack(app, `mfng-aws-app`);
27 changes: 27 additions & 0 deletions apps/aws-app/cdk/waf-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as cdk from 'aws-cdk-lib';
import type {Construct} from 'constructs';

export class WafStack extends cdk.Stack {
#webAcl: cdk.aws_wafv2.CfnWebACL;

constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

this.#webAcl = new cdk.aws_wafv2.CfnWebACL(this, `waf`, {
name: `mfng-waf`,
scope: `CLOUDFRONT`,
defaultAction: {
allow: {},
},
visibilityConfig: {
cloudWatchMetricsEnabled: false,
metricName: `mfng-waf-metric`,
sampledRequestsEnabled: true,
},
});
}

get webAcl(): cdk.aws_wafv2.CfnWebACL {
return this.#webAcl;
}
}
4 changes: 2 additions & 2 deletions apps/aws-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"scripts": {
"build": "NODE_OPTIONS='--import=tsx --conditions=@mfng:internal' webpack --mode production",
"build:dev": "NODE_OPTIONS='--import=tsx --conditions=@mfng:internal' webpack --mode development",
"predeploy": "cdk bootstrap --app 'tsx cdk/stack.ts'",
"deploy": "cdk diff --app 'tsx cdk/stack.ts' && cdk deploy --app 'tsx cdk/stack.ts'",
"predeploy": "cdk bootstrap --app 'tsx cdk/app.ts'",
"deploy": "cdk diff --app 'tsx cdk/app.ts' && cdk deploy --app 'tsx cdk/app.ts' --all",
"dev": "npm start",
"start": "tsx watch --clear-screen=false --enable-source-maps --inspect dev-server/run.ts",
"watch": "NODE_OPTIONS='--import=tsx --conditions=@mfng:internal' webpack --mode production --watch",
Expand Down

0 comments on commit 88c81c1

Please sign in to comment.