Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cloudfront): Origin Shield support #15453

Merged
merged 10 commits into from
Jul 30, 2021
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-cloudfront/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -590,13 +590,15 @@ new CloudFrontWebDistribution(stack, 'ADistribution', {
originHeaders: {
'myHeader': '42',
},
originShieldRegion: 'us-west-2'
},
failoverS3OriginSource: {
s3BucketSource: s3.Bucket.fromBucketName(stack, 'aBucketFallback', 'myoriginbucketfallback'),
originPath: '/somewhere',
originHeaders: {
'myHeader2': '21',
},
originShieldRegion: 'us-east-1'
},
failoverCriteriaStatusCodes: [FailoverStatusCode.INTERNAL_SERVER_ERROR],
behaviors: [
Expand Down
25 changes: 25 additions & 0 deletions packages/@aws-cdk/aws-cloudfront/lib/origin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ export interface OriginProps {
* @default {}
*/
readonly customHeaders?: Record<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;
}

/**
Expand All @@ -106,6 +115,7 @@ export abstract class OriginBase implements IOrigin {
private readonly connectionTimeout?: Duration;
private readonly connectionAttempts?: number;
private readonly customHeaders?: Record<string, string>;
private readonly originShieldRegion?: string

protected constructor(domainName: string, props: OriginProps = {}) {
validateIntInRangeOrUndefined('connectionTimeout', 1, 10, props.connectionTimeout?.toSeconds());
Expand All @@ -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;
}

/**
Expand All @@ -139,6 +150,7 @@ export abstract class OriginBase implements IOrigin {
originCustomHeaders: this.renderCustomHeaders(),
s3OriginConfig,
customOriginConfig,
originShield: this.renderOriginShield(this.originShieldRegion),
},
};
}
Expand Down Expand Up @@ -172,6 +184,19 @@ 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 renderOriginShield(originShieldRegion?: string): CfnDistribution.OriginShieldProperty | undefined {
if (originShieldRegion) {
return {
enabled: true,
originShieldRegion,
};
}
return undefined;
smguggen marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
Expand Down
53 changes: 53 additions & 0 deletions packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ interface SourceConfigurationRender {
readonly customOriginSource?: CustomOriginConfig;
readonly originPath?: string;
readonly originHeaders?: { [key: string]: string };
readonly originShieldRegion?: string
}

/**
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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;
njlynch marked this conversation as resolved.
Show resolved Hide resolved
}

export enum OriginSslPolicy {
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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,
);
Expand Down Expand Up @@ -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[] = [];
Expand Down Expand Up @@ -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,
Expand All @@ -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.`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're removing the region validation from the Distribution, might as well remove it from here for consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, missed that one, I removed it and went ahead and made that return use a ternary operator too.

return {
enabled: true,
originShieldRegion,
};
}
return undefined;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-cloudfront/test/origin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,17 @@ 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,
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ nodeunitShim({
customOriginSource: {
domainName: 'myorigin.com',
},
originShieldRegion: 'us-east-1',
behaviors: [
{
isDefaultBehavior: true,
Expand Down Expand Up @@ -108,6 +109,10 @@ nodeunitShim({
'HeaderValue': 'somevalue',
},
],
'OriginShield': {
'Enabled': true,
'OriginShieldRegion': 'us-east-1',
},
},
],
'PriceClass': 'PriceClass_100',
Expand Down