diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts index b04c6fa1b0e2b..898129517d828 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts @@ -19,6 +19,8 @@ test('Renders minimal example with just a domain name', () => { expect(originBindConfig.originProperty).toEqual({ id: 'StackOrigin029E19582', domainName: 'www.example.com', + originCustomHeaders: undefined, + originPath: undefined, customOriginConfig: { originProtocolPolicy: 'https-only', originSslProtocols: [ diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts index a5a85cde311c6..e732c7b4ecc10 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin.ts @@ -82,6 +82,13 @@ export interface OriginOptions { */ readonly originShieldRegion?: string; + /** + * Origin Shield is enabled by setting originShieldRegion to a valid region, after this to disable Origin Shield again you must set this flag to false. + * + * @default - true + */ + readonly originShieldEnabled?: boolean; + /** * A unique identifier for the origin. This value must be unique within the distribution. * @@ -114,6 +121,7 @@ export interface OriginBindOptions { readonly originId: string; } + /** * Represents a distribution origin, that describes the Amazon S3 bucket, HTTP server (for example, a web server), * Amazon MediaStore, or other server from which CloudFront gets your files. @@ -124,7 +132,8 @@ export abstract class OriginBase implements IOrigin { private readonly connectionTimeout?: Duration; private readonly connectionAttempts?: number; private readonly customHeaders?: Record; - private readonly originShieldRegion?: string + private readonly originShieldRegion?: string; + private readonly originShieldEnabled: boolean; private readonly originId?: string; protected constructor(domainName: string, props: OriginProps = {}) { @@ -139,6 +148,7 @@ export abstract class OriginBase implements IOrigin { this.customHeaders = props.customHeaders; this.originShieldRegion = props.originShieldRegion; this.originId = props.originId; + this.originShieldEnabled = props.originShieldEnabled ?? true; } /** @@ -162,7 +172,7 @@ export abstract class OriginBase implements IOrigin { originCustomHeaders: this.renderCustomHeaders(), s3OriginConfig, customOriginConfig, - originShield: this.renderOriginShield(this.originShieldRegion), + originShield: this.renderOriginShield(this.originShieldEnabled, this.originShieldRegion), }, }; } @@ -200,10 +210,11 @@ export abstract class OriginBase implements IOrigin { /** * Takes origin shield region and converts to CfnDistribution.OriginShieldProperty */ - private renderOriginShield(originShieldRegion?: string): CfnDistribution.OriginShieldProperty | undefined { - return originShieldRegion - ? { enabled: true, originShieldRegion } - : undefined; + private renderOriginShield(originShieldEnabled: boolean, originShieldRegion?: string): CfnDistribution.OriginShieldProperty | undefined { + if (!originShieldEnabled) { + return { enabled: false }; + } + return originShieldRegion ? { enabled: true, originShieldRegion } : undefined; } } diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.assets.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.assets.json new file mode 100644 index 0000000000000..91c2e221fe665 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.template.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/cdk.out b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ-distribution-origin-shield.assets.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ-distribution-origin-shield.assets.json new file mode 100644 index 0000000000000..76a7ebe3666e3 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ-distribution-origin-shield.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "2dad510c7288df819a57567a15bdbfd3396640d1c4a5b7dbb139c67cc8cd290a": { + "source": { + "path": "integ-distribution-origin-shield.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "2dad510c7288df819a57567a15bdbfd3396640d1c4a5b7dbb139c67cc8cd290a.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ-distribution-origin-shield.template.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ-distribution-origin-shield.template.json new file mode 100644 index 0000000000000..5230e0f8fa368 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ-distribution-origin-shield.template.json @@ -0,0 +1,66 @@ +{ + "Resources": { + "DistB3B78991": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "DefaultCacheBehavior": { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "TargetOriginId": "integdistributionoriginshieldDistOrigin11F51234E", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "CustomOriginConfig": { + "OriginProtocolPolicy": "https-only" + }, + "DomainName": "www.example.com", + "Id": "integdistributionoriginshieldDistOrigin11F51234E", + "OriginShield": { + "Enabled": false + } + } + ] + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ.json new file mode 100644 index 0000000000000..4c7a19df4c0fc --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "DistributionOriginShield/DefaultTest": { + "stacks": [ + "integ-distribution-origin-shield" + ], + "assertionStack": "DistributionOriginShield/DefaultTest/DeployAssert", + "assertionStackName": "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/manifest.json new file mode 100644 index 0000000000000..c1c337928eaac --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/manifest.json @@ -0,0 +1,111 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "integ-distribution-origin-shield.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-distribution-origin-shield.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-distribution-origin-shield": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-distribution-origin-shield.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/2dad510c7288df819a57567a15bdbfd3396640d1c4a5b7dbb139c67cc8cd290a.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-distribution-origin-shield.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integ-distribution-origin-shield.assets" + ], + "metadata": { + "/integ-distribution-origin-shield/Dist/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DistB3B78991" + } + ], + "/integ-distribution-origin-shield/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-distribution-origin-shield/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-distribution-origin-shield" + }, + "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "DistributionOriginShieldDefaultTestDeployAssertDF7E33F9.assets" + ], + "metadata": { + "/DistributionOriginShield/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/DistributionOriginShield/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "DistributionOriginShield/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/tree.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/tree.json new file mode 100644 index 0000000000000..557805c92985b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.js.snapshot/tree.json @@ -0,0 +1,122 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.140" + } + }, + "integ-distribution-origin-shield": { + "id": "integ-distribution-origin-shield", + "path": "integ-distribution-origin-shield", + "children": { + "Dist": { + "id": "Dist", + "path": "integ-distribution-origin-shield/Dist", + "children": { + "Origin1": { + "id": "Origin1", + "path": "integ-distribution-origin-shield/Dist/Origin1", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.140" + } + }, + "Resource": { + "id": "Resource", + "path": "integ-distribution-origin-shield/Dist/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "origins": [ + { + "domainName": "www.example.com", + "id": "integdistributionoriginshieldDistOrigin11F51234E", + "customOriginConfig": { + "originProtocolPolicy": "https-only" + }, + "originShield": { + "enabled": false + } + } + ], + "defaultCacheBehavior": { + "pathPattern": "*", + "targetOriginId": "integdistributionoriginshieldDistOrigin11F51234E", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + "httpVersion": "http2", + "ipv6Enabled": true + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnDistribution", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.Distribution", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "DistributionOriginShield": { + "id": "DistributionOriginShield", + "path": "DistributionOriginShield", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "DistributionOriginShield/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "DistributionOriginShield/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.140" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "DistributionOriginShield/DefaultTest/DeployAssert", + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.ts new file mode 100644 index 0000000000000..ddc62afcabf2f --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-origin-shield.ts @@ -0,0 +1,21 @@ +import * as cdk from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; +import * as cloudfront from '../lib'; +import { TestOrigin } from './test-origin'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integ-distribution-origin-shield'); + +new cloudfront.Distribution(stack, 'Dist', { + defaultBehavior: { + origin: new TestOrigin('www.example.com', { + originShieldEnabled: false, + }), + }, +}); + +new IntegTest(app, 'DistributionOriginShield', { + testCases: [stack], +}); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts index 38829cd484ee3..a365810364d66 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts @@ -67,6 +67,29 @@ test.each(['us-east-1', 'ap-southeast-2', 'eu-west-3', 'me-south-1']) }); }); + +test('ensures originShield doesnt return false if undefined', () => { + const origin = new TestOrigin('www.example.com', { + + }); + const originBindConfig = origin.bind(stack, { originId: '0' }); + + expect(originBindConfig.originProperty?.originShield).toBeUndefined(); +}); + + +test('ensures originShield is disabled if originShieldEnabled equals false', () => { + const origin = new TestOrigin('www.example.com', { + originShieldEnabled: false, + }); + const originBindConfig = origin.bind(stack, { originId: '0' }); + + expect(originBindConfig.originProperty?.originShield).toEqual({ + enabled: false, + }); +}); + + test('throw an error if Custom Headers keys are not permitted', () => { // case sensitive expect(() => {