From 43b8be4cda37f458ec285b20be4a752343044a27 Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Wed, 7 Jul 2021 13:42:15 -0500 Subject: [PATCH 1/8] Added Origin Shield to Cloudfront --- packages/@aws-cdk/aws-cloudfront/README.md | 2 + .../@aws-cdk/aws-cloudfront/lib/origin.ts | 26 +++++++++ .../aws-cloudfront/lib/web-distribution.ts | 53 +++++++++++++++++++ ...integ.distribution-extensive.expected.json | 6 ++- .../test/integ.distribution-extensive.ts | 6 ++- .../aws-cloudfront/test/origin.test.ts | 24 +++++++++ .../test/web-distribution.test.ts | 5 ++ 7 files changed, 120 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index 88fc86156a2e2..df22825de95e9 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -590,6 +590,7 @@ new CloudFrontWebDistribution(stack, 'ADistribution', { originHeaders: { 'myHeader': '42', }, + originShieldRegion: 'us-west-2' }, failoverS3OriginSource: { s3BucketSource: s3.Bucket.fromBucketName(stack, 'aBucketFallback', 'myoriginbucketfallback'), @@ -597,6 +598,7 @@ new CloudFrontWebDistribution(stack, 'ADistribution', { originHeaders: { 'myHeader2': '21', }, + originShieldRegion: 'us-east-1' }, failoverCriteriaStatusCodes: [FailoverStatusCode.INTERNAL_SERVER_ERROR], behaviors: [ diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts index 6f5a42e407e01..3d07f005a0e25 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts @@ -83,6 +83,15 @@ export interface OriginProps { * @default {} */ readonly customHeaders?: Record; + + /** + * When you enable Origin Shield in the AWS Region that has the lowest latency to your origin, you can get better network performance + * + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/origin-shield.html + * + * @default - origin shield not enabled + */ + readonly originShieldRegion?: string; } /** @@ -106,6 +115,7 @@ export abstract class OriginBase implements IOrigin { private readonly connectionTimeout?: Duration; private readonly connectionAttempts?: number; private readonly customHeaders?: Record; + private readonly originShieldRegion?: string protected constructor(domainName: string, props: OriginProps = {}) { validateIntInRangeOrUndefined('connectionTimeout', 1, 10, props.connectionTimeout?.toSeconds()); @@ -116,6 +126,7 @@ export abstract class OriginBase implements IOrigin { this.connectionTimeout = props.connectionTimeout; this.connectionAttempts = props.connectionAttempts; this.customHeaders = props.customHeaders; + this.originShieldRegion = props.originShieldRegion; } /** @@ -139,6 +150,7 @@ export abstract class OriginBase implements IOrigin { originCustomHeaders: this.renderCustomHeaders(), s3OriginConfig, customOriginConfig, + originShield: this.getOriginShield(this.originShieldRegion), }, }; } @@ -172,6 +184,20 @@ export abstract class OriginBase implements IOrigin { if (path.endsWith('/')) { path = path.substr(0, path.length - 1); } return path; } + + /** + * Takes origin shield region and converts to CfnDistribution.OriginShieldProperty + */ + private getOriginShield(originShieldRegion:string = ''): CfnDistribution.OriginShieldProperty | undefined { + if (originShieldRegion) { + if (!(/^\w\w\-[a-z]*\-\d$/).test(originShieldRegion)) throw new Error(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); + return { + enabled: true, + originShieldRegion, + }; + } + return undefined; + } } /** diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index db8db2b2bdeb4..14dd629662e06 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -123,6 +123,7 @@ interface SourceConfigurationRender { readonly customOriginSource?: CustomOriginConfig; readonly originPath?: string; readonly originHeaders?: { [key: string]: string }; + readonly originShieldRegion?: string } /** @@ -202,6 +203,15 @@ export interface SourceConfiguration { * @deprecated Use originHeaders on s3OriginSource or customOriginSource */ readonly originHeaders?: { [key: string]: string }; + + /** + * When you enable Origin Shield in the AWS Region that has the lowest latency to your origin, you can get better network performance + * + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/origin-shield.html + * + * @default - origin shield not enabled + */ + readonly originShieldRegion?: string; } /** @@ -268,6 +278,13 @@ export interface CustomOriginConfig { * @default - No additional headers are passed. */ readonly originHeaders?: { [key: string]: string }; + + /** + * When you enable Origin Shield in the AWS Region that has the lowest latency to your origin, you can get better network performance + * + * @default - origin shield not enabled + */ + readonly originShieldRegion?: string; } export enum OriginSslPolicy { @@ -306,6 +323,13 @@ export interface S3OriginConfig { * @default - No additional headers are passed. */ readonly originHeaders?: { [key: string]: string }; + + /** + * When you enable Origin Shield in the AWS Region that has the lowest latency to your origin, you can get better network performance + * + * @default - origin shield not enabled + */ + readonly originShieldRegion?: string; } /** @@ -814,6 +838,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu customOriginSource: originConfig.failoverCustomOriginSource, originPath: originConfig.originPath, originHeaders: originConfig.originHeaders, + originShieldRegion: originConfig.originShieldRegion, }, originSecondaryId, ); @@ -1032,6 +1057,14 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu throw new Error('Only one originPath field allowed across origin and failover origins'); } + if ([ + originConfig.originShieldRegion, + originConfig.s3OriginSource?.originShieldRegion, + originConfig.customOriginSource?.originShieldRegion, + ].filter(x => x).length > 1) { + throw new Error('Only one originShieldRegion field allowed across origin and failover origins'); + } + const headers = originConfig.originHeaders ?? originConfig.s3OriginSource?.originHeaders ?? originConfig.customOriginSource?.originHeaders; const originHeaders: CfnDistribution.OriginCustomHeaderProperty[] = []; @@ -1087,6 +1120,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu originCustomHeaders: originHeaders.length > 0 ? originHeaders : undefined, s3OriginConfig, + originShield: this.toOriginShieldProperty(originConfig), customOriginConfig: originConfig.customOriginSource ? { httpPort: originConfig.customOriginSource.httpPort || 80, @@ -1112,4 +1146,23 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu return originProperty; } + + /** + * Takes origin shield region from props and converts to CfnDistribution.OriginShieldProperty + */ + private toOriginShieldProperty(originConfig:SourceConfigurationRender): CfnDistribution.OriginShieldProperty | undefined { + const originShieldRegion = originConfig.originShieldRegion ?? + originConfig.customOriginSource?.originShieldRegion ?? + originConfig.s3OriginSource?.originShieldRegion; + if (originShieldRegion) { + if (!(/^\w\w\-[a-z]*\-\d$/).test(originShieldRegion)) { + throw new Error(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); + } + return { + enabled: true, + originShieldRegion, + }; + } + return undefined; + } } diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json index 56829919d2306..4ddd5ddb8d373 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json @@ -36,7 +36,11 @@ "OriginProtocolPolicy": "https-only" }, "DomainName": "www.example.com", - "Id": "integdistributionextensiveMyDistOrigin185F089B3" + "Id": "integdistributionextensiveMyDistOrigin185F089B3", + "OriginShield": { + "Enabled": true, + "OriginShieldRegion": "us-west-2" + } } ], "PriceClass": "PriceClass_100", diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts index 6a8f949ca9b43..fa55fe571326d 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts @@ -6,7 +6,11 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'integ-distribution-extensive'); new cloudfront.Distribution(stack, 'MyDist', { - defaultBehavior: { origin: new TestOrigin('www.example.com') }, + defaultBehavior: { + origin: new TestOrigin('www.example.com', { + originShieldRegion: 'us-west-2', + }), + }, comment: 'a test', defaultRootObject: 'index.html', enabled: true, diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts index b2a60a2fd109d..75ae57b458aa7 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts @@ -44,3 +44,27 @@ test.each(['api', '/api', '/api/', 'api/']) expect(originBindConfig.originProperty?.originPath).toEqual('/api'); }); + + +test.each(['us-east-1', 'ap-southeast-2', 'eu-west-3', 'me-south-1']) +('ensures that originShieldRegion is a valid aws region', (originShieldRegion) => { + const origin = new TestOrigin('www.example.com', { + originShieldRegion, + }); + const originBindConfig = origin.bind(stack, { originId: '0' }); + + expect(originBindConfig.originProperty?.originShield).toEqual({ + enabled: true, + originShieldRegion, + }); +}); + +test.each(['region', 'nowhere-2', 'place-west-3', 'me-south-one']) +('throws when originShieldRegion is not a valid aws region', (originShieldRegion) => { + const origin = new TestOrigin('www.example.com', { + originShieldRegion, + }); + expect(() => { + origin.bind(stack, { originId: '0' }); + }).toThrow(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts index 517aa18b3364c..14be6d72b8348 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -47,6 +47,7 @@ nodeunitShim({ customOriginSource: { domainName: 'myorigin.com', }, + originShieldRegion: 'us-east-1', behaviors: [ { isDefaultBehavior: true, @@ -108,6 +109,10 @@ nodeunitShim({ 'HeaderValue': 'somevalue', }, ], + 'OriginShield': { + 'Enabled': true, + 'OriginShieldRegion': 'us-east-1', + }, }, ], 'PriceClass': 'PriceClass_100', From ace90a7fbd4572613ebc07ae1536480806d07248 Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Thu, 29 Jul 2021 08:54:01 -0500 Subject: [PATCH 2/8] Update packages/@aws-cdk/aws-cloudfront/lib/origin.ts Co-authored-by: Nick Lynch --- packages/@aws-cdk/aws-cloudfront/lib/origin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts index 3d07f005a0e25..05728c083ad5b 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts @@ -187,7 +187,7 @@ export abstract class OriginBase implements IOrigin { /** * Takes origin shield region and converts to CfnDistribution.OriginShieldProperty - */ + */ private getOriginShield(originShieldRegion:string = ''): CfnDistribution.OriginShieldProperty | undefined { if (originShieldRegion) { if (!(/^\w\w\-[a-z]*\-\d$/).test(originShieldRegion)) throw new Error(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); From 81208a0cea1bbff8549977ea46dec1cd73442e5c Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Thu, 29 Jul 2021 08:54:57 -0500 Subject: [PATCH 3/8] Change getOriginShield method name to renderOriginShield Co-authored-by: Nick Lynch --- packages/@aws-cdk/aws-cloudfront/lib/origin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts index 05728c083ad5b..1b68750d12f64 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts @@ -188,7 +188,7 @@ export abstract class OriginBase implements IOrigin { /** * Takes origin shield region and converts to CfnDistribution.OriginShieldProperty */ - private getOriginShield(originShieldRegion:string = ''): CfnDistribution.OriginShieldProperty | undefined { + private renderOriginShield(originShieldRegion?: string): CfnDistribution.OriginShieldProperty | undefined { if (originShieldRegion) { if (!(/^\w\w\-[a-z]*\-\d$/).test(originShieldRegion)) throw new Error(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); return { From 764580364f2328266c86ed7a50b89e203538a009 Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Thu, 29 Jul 2021 09:00:34 -0500 Subject: [PATCH 4/8] Remove region validation, update getOriginShield calls --- packages/@aws-cdk/aws-cloudfront/lib/origin.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts index 1b68750d12f64..5cff527aa3837 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts @@ -150,7 +150,7 @@ export abstract class OriginBase implements IOrigin { originCustomHeaders: this.renderCustomHeaders(), s3OriginConfig, customOriginConfig, - originShield: this.getOriginShield(this.originShieldRegion), + originShield: this.renderOriginShield(this.originShieldRegion), }, }; } @@ -190,7 +190,6 @@ export abstract class OriginBase implements IOrigin { */ private renderOriginShield(originShieldRegion?: string): CfnDistribution.OriginShieldProperty | undefined { if (originShieldRegion) { - if (!(/^\w\w\-[a-z]*\-\d$/).test(originShieldRegion)) throw new Error(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); return { enabled: true, originShieldRegion, From ffb107ca730394515d8ec3900622d422ea8f7097 Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Thu, 29 Jul 2021 09:45:38 -0500 Subject: [PATCH 5/8] Remove tests for valid region --- packages/@aws-cdk/aws-cloudfront/test/origin.test.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts index 75ae57b458aa7..b30362c7fe652 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts @@ -57,14 +57,4 @@ test.each(['us-east-1', 'ap-southeast-2', 'eu-west-3', 'me-south-1']) enabled: true, originShieldRegion, }); -}); - -test.each(['region', 'nowhere-2', 'place-west-3', 'me-south-one']) -('throws when originShieldRegion is not a valid aws region', (originShieldRegion) => { - const origin = new TestOrigin('www.example.com', { - originShieldRegion, - }); - expect(() => { - origin.bind(stack, { originId: '0' }); - }).toThrow(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); }); \ No newline at end of file From d1efb1de418857c173bac2263908d2551d72fb11 Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Thu, 29 Jul 2021 11:54:22 -0500 Subject: [PATCH 6/8] Convert result of renderOriginShield to use ternary operator Co-authored-by: Nick Lynch --- packages/@aws-cdk/aws-cloudfront/lib/origin.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts index 5cff527aa3837..9b841e413c405 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts @@ -189,13 +189,9 @@ export abstract class OriginBase implements IOrigin { * Takes origin shield region and converts to CfnDistribution.OriginShieldProperty */ private renderOriginShield(originShieldRegion?: string): CfnDistribution.OriginShieldProperty | undefined { - if (originShieldRegion) { - return { - enabled: true, - originShieldRegion, - }; - } - return undefined; + return originShieldRegion + ? { enabled: true, originShieldRegion } + : undefined; } } From 482abb2439141f090fb654c42667429794b26251 Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Thu, 29 Jul 2021 12:04:29 -0500 Subject: [PATCH 7/8] Removed region validation and converted return value to use ternary operator on toOriginShieldProperty method --- .../aws-cloudfront/lib/web-distribution.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index 14dd629662e06..26ddf899522cf 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -1149,20 +1149,13 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu /** * Takes origin shield region from props and converts to CfnDistribution.OriginShieldProperty - */ + */ private toOriginShieldProperty(originConfig:SourceConfigurationRender): CfnDistribution.OriginShieldProperty | undefined { const originShieldRegion = originConfig.originShieldRegion ?? originConfig.customOriginSource?.originShieldRegion ?? originConfig.s3OriginSource?.originShieldRegion; - if (originShieldRegion) { - if (!(/^\w\w\-[a-z]*\-\d$/).test(originShieldRegion)) { - throw new Error(`originShieldRegion ${originShieldRegion} is not a valid AWS region.`); - } - return { - enabled: true, - originShieldRegion, - }; - } - return undefined; + return originShieldRegion + ? { enabled: true, originShieldRegion } + : undefined; } } From 725f4879ebfdb5578ba9eafc2a4461e8aa8337ac Mon Sep 17 00:00:00 2001 From: Steven Guggenheimer Date: Thu, 29 Jul 2021 14:43:53 -0500 Subject: [PATCH 8/8] Remove trailing spaces from previous change --- packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index 26ddf899522cf..f9427c03dd452 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -1154,8 +1154,8 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu const originShieldRegion = originConfig.originShieldRegion ?? originConfig.customOriginSource?.originShieldRegion ?? originConfig.s3OriginSource?.originShieldRegion; - return originShieldRegion - ? { enabled: true, originShieldRegion } + return originShieldRegion + ? { enabled: true, originShieldRegion } : undefined; } }