From f13f486d5bc9255bc053d788cbb02c33e8252947 Mon Sep 17 00:00:00 2001 From: Henry Goffin Date: Wed, 29 Mar 2023 02:55:53 +0000 Subject: [PATCH 1/7] implement cloudfront.OriginAccessControl construct --- .../aws-cloudfront-origins/lib/s3-origin.ts | 137 ++++++- .../test/s3-origin.test.ts | 134 +++++- packages/@aws-cdk/aws-cloudfront/README.md | 73 ++-- .../aws-cloudfront/lib/distribution.ts | 13 + packages/@aws-cdk/aws-cloudfront/lib/index.ts | 1 + .../lib/origin-access-control.ts | 226 ++++++++++ .../aws-cloudfront/lib/web-distribution.ts | 39 +- ...efaultTestDeployAssertEF946D96.assets.json | 19 + ...aultTestDeployAssertEF946D96.template.json | 36 ++ .../cdk.out | 1 + .../integ-cloudfront-s3-oac-l2.assets.json | 19 + .../integ-cloudfront-s3-oac-l2.template.json | 218 ++++++++++ .../integ.json | 12 + .../manifest.json | 141 +++++++ .../tree.json | 388 ++++++++++++++++++ .../test/integ.cloudfront-s3-oac-l2.ts | 49 +++ ...efaultTestDeployAssertFF6C26DC.assets.json | 19 + ...aultTestDeployAssertFF6C26DC.template.json | 36 ++ .../cdk.out | 1 + .../integ-cloudfront-s3-oac.assets.json | 19 + .../integ-cloudfront-s3-oac.template.json | 105 +++++ .../integ.json | 12 + .../manifest.json | 123 ++++++ .../tree.json | 219 ++++++++++ .../test/integ.cloudfront-s3-oac.ts | 40 ++ .../@aws-cdk/aws-cloudfront/test/oac.test.ts | 166 ++++++++ .../test/web-distribution.test.ts | 50 +++ 27 files changed, 2255 insertions(+), 41 deletions(-) create mode 100644 packages/@aws-cdk/aws-cloudfront/lib/origin-access-control.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.assets.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.assets.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.assets.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.assets.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/oac.test.ts diff --git a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts index d2003c9285571..fd81dd930a6ba 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts @@ -1,18 +1,75 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; +import { OriginAccessControl } from '@aws-cdk/aws-cloudfront'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { HttpOrigin } from './http-origin'; +/** + * Resource policy modification settings for S3 origins. + */ +export enum S3OriginAutoResourcePolicy { + /** + * No modifications are made to resource policies + */ + NONE = 'none', + /** + * Read (but not write) permissions are added to resource policies + */ + READ_ONLY = 'readonly', + /** + * Read and write permissions are added to resource policies. + * This setting cannot be used with origin access identity (OAI). + */ + READ_WRITE = 'readwrite', +}; + /** * Properties to use to customize an S3 Origin. */ export interface S3OriginProps extends cloudfront.OriginProps { /** - * An optional Origin Access Identity of the origin identity cloudfront will use when calling your s3 bucket. + * Controls how the resource policies of origin buckets and keys should be automatically modified. + * The behavior is slightly different for "origin access control" (OAC) and "origin access identity" + * (OAI) origin configurations. + * + * If this property is NONE, then no modifications are made to any resource policies. S3 bucket + * policy must be configured manually to grant necessary permissions to the CloudFront distribution. + * + * If this property is READ_ONLY, then s3:GetObject and kms:Decrypt permissions are granted to the + * CloudFront distribution on the bucket and its associated KMS key, if any. + * + * If this property is READ_WRITE, then s3:PutObject, kms:Encrypt, and kms:GenerateDataKey* permissions + * are granted to the CloudFront distrubution on the bucket and its associated KMS key, if any. + * + * When used in combination with OAC, the described behavior is mandatory. If any resource policies + * cannot be set due to imported or cross-stack resources, an error will be raised. + * + * When used in a stack with a legacy OAI configuration, only a best-effort attempt will be made to set + * resource policies. Any failures due to imported or cross-stack resources will be ignored. + * + * @default S3OriginAutoResourcePolicyConfig.READ_ONLY + */ + readonly autoResourcePolicy?: S3OriginAutoResourcePolicy; + /** + * An optional "origin access control" (OAC) resource which describes how the distribution should + * sign its requests for the S3 bucket origin. Can also be set to `true` to apply a default OAC. + * OAC is the preferred way to authenticate S3 requests and should be enabled whenever possible. + * + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html + * + * @default - OAC is disabled by default, `originAccessIdentity` settings will be used insead + */ + readonly originAccessControl?: cloudfront.IOriginAccessControl | true; + /** + * An optional "origin access identity" (OAI) that CloudFront will use to access the S3 bucket. + * OAI is a legacy feature which remains enabled by default for backwards-compatibility reasons. + * New origin configurations should use OAC instead, via the `originAccessControl` property. * - * @default - An Origin Access Identity will be created. + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html + * + * @default - OAI is enabled with default settings, unless `originAccessControl` is set */ readonly originAccessIdentity?: cloudfront.IOriginAccessIdentity; } @@ -47,16 +104,56 @@ export class S3Origin implements cloudfront.IOrigin { * Contains additional logic around bucket permissions and origin access identities. */ class S3BucketOrigin extends cloudfront.OriginBase { - private originAccessIdentity!: cloudfront.IOriginAccessIdentity; - constructor(private readonly bucket: s3.IBucket, { originAccessIdentity, ...props }: S3OriginProps) { + private originAccessControl?: cloudfront.IOriginAccessControl | true; + private originAccessIdentity?: cloudfront.IOriginAccessIdentity; + private autoResourcePolicy: S3OriginAutoResourcePolicy; + + constructor(private readonly bucket: s3.IBucket, props: S3OriginProps) { super(bucket.bucketRegionalDomainName, props); - if (originAccessIdentity) { - this.originAccessIdentity = originAccessIdentity; + if (props.originAccessControl && props.originAccessIdentity) { + throw new Error('The same origin cannot specify both originAccessControl and originAccessIdentity'); } + this.originAccessControl = props.originAccessControl; + this.originAccessIdentity = props.originAccessIdentity; + this.autoResourcePolicy = props.autoResourcePolicy ?? S3OriginAutoResourcePolicy.READ_ONLY; } public bind(scope: Construct, options: cloudfront.OriginBindOptions): cloudfront.OriginBindConfig { + if (this.originAccessControl) { + if (this.autoResourcePolicy != S3OriginAutoResourcePolicy.NONE) { + const readonly = this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_ONLY; + const dist = scope.node.scope as cloudfront.Distribution; + const lazyDistArn = cdk.Lazy.string({ produce: () => dist.distributionArn }); + const added = this.bucket.addToResourcePolicy(new iam.PolicyStatement({ + principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')], + actions: readonly ? ['s3:GetObject'] : ['s3:GetObject', 's3:PutObject'], + resources: [this.bucket.arnForObjects('*')], + conditions: { StringEquals: { 'aws:SourceArn': lazyDistArn } }, + })); + if (!added.statementAdded) { + throw new Error('S3Origin cannot edit imported buckets, try autoResourcePolicy=NONE'); + } + // Buckets work because the bucket policies are only installed after the bucket + // is created, so the bucket policy can have a dependency on the distribution + // which depends on the bucket. But KMS keys need their policy at creation time, + // and there is no way to break the circular dependency with the distribution... + // unless we write a custom resource Lambda that modifies the key policy "later"? + if (this.bucket.encryptionKey) { + throw new Error('S3Origin cannot edit KMS keys at this time, try autoResourcePolicy=NONE'); + } + } + let oac = this.originAccessControl; + if (oac === true) { + oac = OriginAccessControl.fromS3Defaults(scope); + } + const newBindConfig = { ...super.bind(scope, options) }; + const newOriginProp = { ...newBindConfig.originProperty! }; + newOriginProp.originAccessControlId = oac.originAccessControlId; + newBindConfig.originProperty = newOriginProp; + return newBindConfig; + } + if (!this.originAccessIdentity) { // Using a bucket from another stack creates a cyclic reference with // the bucket taking a dependency on the generated S3CanonicalUserId for the grant principal, @@ -71,19 +168,27 @@ class S3BucketOrigin extends cloudfront.OriginBase { comment: `Identity for ${options.originId}`, }); } - // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. - // Only GetObject is needed to retrieve objects for the distribution. - // This also excludes KMS permissions; currently, OAI only supports SSE-S3 for buckets. - // Source: https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/ - this.bucket.addToResourcePolicy(new iam.PolicyStatement({ - resources: [this.bucket.arnForObjects('*')], - actions: ['s3:GetObject'], - principals: [this.originAccessIdentity.grantPrincipal], - })); + if (this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_WRITE) { + throw new Error('S3OriginAutoResourcePolicy.READ_WRITE is not supported with Origin Access Identity'); + } + if (this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_ONLY) { + // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. + // Only GetObject is needed to retrieve objects for the distribution. + // This also excludes KMS permissions; currently, OAI only supports SSE-S3 for buckets. + // Source: https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/ + this.bucket.addToResourcePolicy(new iam.PolicyStatement({ + resources: [this.bucket.arnForObjects('*')], + actions: ['s3:GetObject'], + principals: [this.originAccessIdentity.grantPrincipal], + })); + } return super.bind(scope, options); } protected renderS3OriginConfig(): cloudfront.CfnDistribution.S3OriginConfigProperty | undefined { - return { originAccessIdentity: `origin-access-identity/cloudfront/${this.originAccessIdentity.originAccessIdentityId}` }; + if (this.originAccessControl) { + return { }; + } + return { originAccessIdentity: `origin-access-identity/cloudfront/${this.originAccessIdentity!.originAccessIdentityId}` }; } } diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts index 7889659db5420..f54b5ba32e792 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts @@ -2,7 +2,7 @@ import { Match, Template } from '@aws-cdk/assertions'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, Stack } from '@aws-cdk/core'; -import { S3Origin } from '../lib'; +import { S3Origin, S3OriginAutoResourcePolicy } from '../lib'; let app: App; let stack: Stack; @@ -153,6 +153,138 @@ describe('With bucket', () => { }); }); + test('can use OriginAccessControl with automatic permissions', () => { + const bucket = new s3.Bucket(stack, 'Bucket'); + const origin = new S3Origin(bucket, { originAccessControl: true }); + new cloudfront.Distribution(stack, 'Dist', { defaultBehavior: { origin } }); + + const oacSingletonRef = 'OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28'; + + const tmpl = Template.fromStack(stack); + tmpl.hasResourceProperties('AWS::CloudFront::OriginAccessControl', { + OriginAccessControlConfig: { + OriginAccessControlOriginType: 's3', + SigningBehavior: 'always', + SigningProtocol: 'sigv4', + }, + }); + tmpl.hasResourceProperties('AWS::CloudFront::Distribution', { + DistributionConfig: { + Origins: [{ + DomainName: Match.exact({ 'Fn::GetAtt': ['Bucket83908E77', 'RegionalDomainName'] }), + OriginAccessControlId: Match.exact({ Ref: oacSingletonRef }), + S3OriginConfig: Match.exact({}), + }], + }, + }); + tmpl.hasResourceProperties('AWS::S3::BucketPolicy', { + PolicyDocument: { + Statement: [{ + Effect: 'Allow', + Action: 's3:GetObject', + Principal: Match.exact({ Service: 'cloudfront.amazonaws.com' }), + Resource: Match.exact({ 'Fn::Join': ['', [Match.anyValue(), '/*']] }), + Condition: Match.exact({ StringEquals: { 'aws:SourceArn': Match.anyValue() } }), + }], + }, + }); + }); + + test('can use OriginAccessControl with read-write permissions', () => { + const bucket = new s3.Bucket(stack, 'Bucket'); + const origin = new S3Origin(bucket, { + originAccessControl: true, + autoResourcePolicy: S3OriginAutoResourcePolicy.READ_WRITE, + }); + new cloudfront.Distribution(stack, 'Dist', { defaultBehavior: { origin } }); + + const oacSingletonRef = 'OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28'; + + const tmpl = Template.fromStack(stack); + tmpl.hasResourceProperties('AWS::CloudFront::OriginAccessControl', { + OriginAccessControlConfig: { + OriginAccessControlOriginType: 's3', + SigningBehavior: 'always', + SigningProtocol: 'sigv4', + }, + }); + tmpl.hasResourceProperties('AWS::CloudFront::Distribution', { + DistributionConfig: { + Origins: [{ + DomainName: Match.exact({ 'Fn::GetAtt': ['Bucket83908E77', 'RegionalDomainName'] }), + OriginAccessControlId: Match.exact({ Ref: oacSingletonRef }), + S3OriginConfig: Match.exact({}), + }], + }, + }); + tmpl.hasResourceProperties('AWS::S3::BucketPolicy', { + PolicyDocument: { + Statement: [{ + Effect: 'Allow', + Action: Match.exact(['s3:GetObject', 's3:PutObject']), + Principal: Match.exact({ Service: 'cloudfront.amazonaws.com' }), + Resource: Match.exact({ 'Fn::Join': ['', [Match.anyValue(), '/*']] }), + Condition: Match.exact({ StringEquals: { 'aws:SourceArn': Match.anyValue() } }), + }], + }, + }); + }); + + false && test('can use OriginAccessCotrol with KMS and automatic permissions', () => { + + // XXX circular dependency! Distribution requires Bucket, Bucket requires Key, + // Key requires Distribution (because key policy can't be set after creation). + // We can crack this by forcing the Distribution to create with enabled=false, + // then use Lambda to adjust Key policy and optionally enable the Distribution. + // Distribution doesn't allow the explicit specification of a distribution ID. + + const bucket = new s3.Bucket(stack, 'Bucket', { encryption: s3.BucketEncryption.KMS }); + const origin = new S3Origin(bucket, { originAccessControl: true }); + new cloudfront.Distribution(stack, 'Dist', { defaultBehavior: { origin } }); + + const oacSingletonRef = 'OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28'; + + const tmpl = Template.fromStack(stack); + tmpl.hasResourceProperties('AWS::CloudFront::OriginAccessControl', { + OriginAccessControlConfig: { + OriginAccessControlOriginType: 's3', + SigningBehavior: 'always', + SigningProtocol: 'sigv4', + }, + }); + tmpl.hasResourceProperties('AWS::CloudFront::Distribution', { + DistributionConfig: { + Origins: [{ + DomainName: Match.exact({ 'Fn::GetAtt': ['Bucket83908E77', 'RegionalDomainName'] }), + OriginAccessControlId: Match.exact({ Ref: oacSingletonRef }), + S3OriginConfig: Match.exact({}), + }], + }, + }); + tmpl.hasResourceProperties('AWS::S3::BucketPolicy', { + PolicyDocument: { + Statement: [{ + Action: 's3:GetObject', + Effect: 'Allow', + Principal: Match.exact({ Service: 'cloudfront.amazonaws.com' }), + Resource: Match.exact({ 'Fn::Join': ['', [Match.anyValue(), '/*']] }), + Condition: Match.exact({ StringEquals: { 'aws:SourceArn': Match.anyValue() } }), + }], + }, + }); + tmpl.hasResourceProperties('AWS::KMS::KeyPolicy', { + PolicyDocument: { + Statement: [{ + Action: 'kms:Decrypt', + Effect: 'Allow', + Principal: Match.exact({ Service: 'cloudfront.amazonaws.com' }), + Resource: '*', + Condition: Match.exact({ StringEquals: { 'aws:SourceArn': Match.anyValue() } }), + }], + }, + }); + }); + test('Can set a custom originId', () => { const bucket = new s3.Bucket(stack, 'Bucket'); const bucket2 = new s3.Bucket(stack, 'Bucket2'); diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index 95e0acb755f13..01544e7d6ea7f 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -33,26 +33,64 @@ Additional behaviors may be specified for an origin with a given URL path patter controlling which HTTP methods to support, whether to require users to use HTTPS, and what query strings or cookies to forward to your origin, among other settings. -#### From an S3 Bucket +#### From any generic HTTP endpoint -An S3 bucket can be added as an origin. If the bucket is configured as a website endpoint, the distribution can use S3 redirects and S3 custom error -documents. +Any public HTTP or HTTPS endpoint can be used as an origin, as long as it has a static domain name. ```ts -// Creates a distribution from an S3 bucket. +// Creates a distribution from an HTTP endpoint +new cloudfront.Distribution(this, 'myDist', { + defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, +}); +``` + +#### From an S3 Bucket with IAM access controls + +Any S3 bucket can be used as an origin. If the bucket is not configured for public website hosting, the distribution +will access bucket contents through the standard S3 `GetObject` API. + +CloudFront supports two methods of authenticating with S3: origin access control (OAC) and origin access identity (OAI). OAI +is a legacy authentication method which will not be supported in new regions. It is strongly recommended to use OAC for all +new deployments. + +You can enable OAC by setting the `originAccessControl` property to `true`, or by explicitly supplying an `OriginAccessControl` +resource. If you leave OAC disabled, the legacy OAI method will be used by default for backwards-compatibility reasons. + +```ts +// Creates a distribution from a private S3 bucket using Origin Access Control const myBucket = new s3.Bucket(this, 'myBucket'); new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.S3Origin(myBucket) }, + defaultBehavior: { origin: new origins.S3Origin(myBucket, { originAccessControl: true }) }, }); ``` -The above will treat the bucket differently based on if `IBucket.isWebsite` is set or not. If the bucket is configured as a website, the bucket is -treated as an HTTP origin, and the built-in S3 redirects and error pages can be used. Otherwise, the bucket is handled as a bucket origin and -CloudFront's redirect and error handling will be used. In the latter case, the Origin will create an origin access identity and grant it access to the -underlying bucket. This can be used in conjunction with a bucket that is not public to require that your users access your content using CloudFront -URLs and not S3 URLs directly. +The `S3Origin` construct will automatically adjust the bucket resource policy to grant necessary `s3:GetObject` permissions. +When using OAC, any failure when adjusting permissions will result in an error message. If you cannot resolve the error, you +can set `autoResourcePolicy: false` to allow deployment and then manually adjust resource policies after deployment. + +When using OAI, some types of failures when adjusting permissions will be silently ignored. You should verify that your +distribution is properly serving origin content after deployment, and then adjust resource policies if necessary. + +See [Restricting access to an Amazon S3 origin](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html) for more details about OAC, OAI, and resource policies. + +#### From a website-enabled S3 Bucket with public read access + +A website-enabled S3 bucket can also be used as an origin. The distribution will access the bucket through +the public website endpoint and honor any existing S3 configuration for index documents, error documents, +and redirections. -#### ELBv2 Load Balancer +```ts +// Creates a distribution from a public website-enabled S3 bucket +const publicWebBucket = new s3.Bucket(this, 'myWebsiteBucket', { + publicReadAccess: true, + websiteIndexDocument: 'index.html', +}); +new cloudfront.Distribution(this, 'myDist', { + defaultBehavior: { origin: new origins.S3Origin(publicWebBucket) }, +}); +``` + +#### From an ELBv2 Load Balancer An Elastic Load Balancing (ELB) v2 load balancer may be used as an origin. In order for a load balancer to serve as an origin, it must be publicly accessible (`internetFacing` is true). Both Application and Network load balancers are supported. @@ -71,17 +109,6 @@ new cloudfront.Distribution(this, 'myDist', { }); ``` -#### From an HTTP endpoint - -Origins can also be created from any other HTTP endpoint, given the domain name, and optionally, other origin properties. - -```ts -// Creates a distribution from an HTTP endpoint -new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, -}); -``` - ### Domain Names and Certificates When you create a distribution, CloudFront assigns a domain name for the distribution, for example: `d111111abcdef8.cloudfront.net`; this value can @@ -1024,7 +1051,7 @@ new cloudfront.KeyGroup(this, 'MyKeyGroup', { }), ], // comment: 'Key group containing public keys ...', -}); +});: ``` See: diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index 790173451dbaf..e971744729f73 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -42,6 +42,15 @@ export interface IDistribution extends IResource { */ readonly distributionId: string; + /** + * The ARN which uniquely identifies this distribution. When Origin Access Control + * is configured, this is the `aws:SourceArn` condition value used when evaluating + * IAM policy checks for origin resources. + * + * @attribute + */ + readonly distributionArn: string; + /** * Adds an IAM policy statement associated with this distribution to an IAM * principal's policy. @@ -268,12 +277,14 @@ export class Distribution extends Resource implements IDistribution { public readonly domainName: string; public readonly distributionDomainName: string; public readonly distributionId: string; + public readonly distributionArn: string; constructor() { super(scope, id); this.domainName = attrs.domainName; this.distributionDomainName = attrs.domainName; this.distributionId = attrs.distributionId; + this.distributionArn = formatDistributionArn(this); } public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { @@ -288,6 +299,7 @@ export class Distribution extends Resource implements IDistribution { public readonly domainName: string; public readonly distributionDomainName: string; public readonly distributionId: string; + public readonly distributionArn: string; private readonly defaultBehavior: CacheBehavior; private readonly additionalBehaviors: CacheBehavior[] = []; @@ -353,6 +365,7 @@ export class Distribution extends Resource implements IDistribution { this.domainName = distribution.attrDomainName; this.distributionDomainName = distribution.attrDomainName; this.distributionId = distribution.ref; + this.distributionArn = formatDistributionArn(this); } /** diff --git a/packages/@aws-cdk/aws-cloudfront/lib/index.ts b/packages/@aws-cdk/aws-cloudfront/lib/index.ts index e5abe99c0bfbd..99ca65ec76a9c 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/index.ts @@ -4,6 +4,7 @@ export * from './function'; export * from './geo-restriction'; export * from './key-group'; export * from './origin'; +export * from './origin-access-control'; export * from './origin-access-identity'; export * from './origin-request-policy'; export * from './public-key'; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin-access-control.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin-access-control.ts new file mode 100644 index 0000000000000..e8e2842d1bf34 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin-access-control.ts @@ -0,0 +1,226 @@ +import * as cdk from '@aws-cdk/core'; +import { md5hash } from '@aws-cdk/core/lib/helpers-internal'; +import { Construct } from 'constructs'; +import { CfnOriginAccessControl } from './cloudfront.generated'; + +/** + * AWS service for which CloudFront Origin Access Control should sign requests + */ +export enum OriginAccessControlOriginType { + /** + * AWS Elemental MediaStore + */ + MEDIASTORE = 'mediastore', + /** + * Amazon S3 + */ + S3 = 's3', +} + +/** + * Configuration of when CloudFront Origin Access Control will sign requests + * + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#oac-advanced-settings + */ +export enum OriginAccessControlSigningBehavior { + /** + * Always sign requests, replacing any existing `Authorization` header + */ + ALWAYS = 'always', + /** + * Never sign requests, effectively disabling Origin Access Control + */ + NEVER = 'never', + /** + * Sign requests only if an `Authorization` header is not already set + * + * *WARNING: You must add the `Authorization` header to the [cache key](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html) policy for all associated origins.* + */ + NO_OVERRIDE = 'no-override', +} + +/** + * Signature protocol used by CloudFront Origin Access Control to sign requests + */ +export enum OriginAccessControlSigningProtocol { + /** + * SIGV4 is the only supported signature type at this time + */ + SIGV4 = 'sigv4', +} + +/** + * Properties of CloudFront Origin Access Control + */ +export interface OriginAccessControlProps { + /** + * A name which uniquely identifies this Origin Access Control within your account + * + * @default - A unique name will be generated from the construct ID + */ + readonly originAccessControlName?: string; + + /** + * An optional description of this Origin Access Control + * + * @default - No description + */ + readonly description?: string; + + /** + * AWS service for which CloudFront Origin Access Control should sign requests + */ + readonly originType: OriginAccessControlOriginType; + + /** + * Configuration of when CloudFront Origin Access Control will sign requests + * + * @default OriginAccessControlSigningBehavior.ALWAYS + */ + readonly signingBehavior?: OriginAccessControlSigningBehavior; + + /** + * Signature protocol used by CloudFront Origin Access Control to sign requests + * + * @default OriginAccessControlSigningProtocol.SIGV4 + */ + readonly signingProtocol?: OriginAccessControlSigningProtocol; +} + +/** + * Interface for CloudFront Origin Access Control + */ +export interface IOriginAccessControl extends cdk.IResource { + /** + * The Origin Access Control ID (Physical ID in CloudFormation) + * + * @attribute + */ + readonly originAccessControlId: string; +} + +/** + * An Origin Access Control is a set of parameters used to control how CloudFront + * distributions authenticate requests to the origin. This functionality replaces + * the older Origin Access Identity authentication feature. + * + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-origin.html + * + * @resource AWS::CloudFront::OriginAccessControl + */ +export class OriginAccessControl extends cdk.Resource implements IOriginAccessControl { + /** + * Imports an existing Origin Access Control by ID + */ + public static fromOriginAccessControlId( + scope: Construct, + id: string, + originAccessControlId: string): IOriginAccessControl { + + class Import extends cdk.Resource implements IOriginAccessControl { + public readonly originAccessControlId: string; + constructor(s: Construct, i: string, oacId: string) { + super(s, i, { physicalName: oacId }); + this.originAccessControlId = oacId; + } + } + + return new Import(scope, id, originAccessControlId); + } + + /** + * Creates an Origin Access Control which signs Amazon S3 requests. If no + * logical construct ID is specified, this will create and manage a singleton + * Origin Access Control within the stack which has suitable default values + * for accessing S3 buckets. + */ + public static fromS3Defaults( + scope: Construct, + id?: string, + behaviorOverride?: OriginAccessControlSigningBehavior): IOriginAccessControl { + + const props = { + originType: OriginAccessControlOriginType.S3, + signingBehavior: behaviorOverride, + }; + if (id === undefined) { + return OriginAccessControl.fromSingleton(cdk.Stack.of(scope), props); + } else { + return new OriginAccessControl(scope, id, props); + } + } + + /** + * Creates an Origin Access Control which signs MediaStore requests. If no + * logical construct ID is specified, this will create and manage a singleton + * Origin Access Control within the stack which has suitable default values + * for accessing MediaStore origins. + */ + public static fromMediaStoreDefaults( + scope: Construct, + id?: string, + behaviorOverride?: OriginAccessControlSigningBehavior): IOriginAccessControl { + + const props = { + originType: OriginAccessControlOriginType.MEDIASTORE, + signingBehavior: behaviorOverride, + }; + if (id === undefined) { + return OriginAccessControl.fromSingleton(cdk.Stack.of(scope), props); + } else { + return new OriginAccessControl(scope, id, props); + } + } + + /** + * Creates or returns an existing Origin Access Control in the target stack + * which matches the given properties. The CDK construct id and CloudFormation + * physical id are both derived from a hash of the properties. + */ + public static fromSingleton(stack: cdk.Stack, props: OriginAccessControlProps) { + props = OriginAccessControl.assignDefaultValues(props); + const hash = md5hash(`OACStackSingleton-${props.originType}-${props.signingProtocol}-${props.signingBehavior}`); + const id = `OriginAccessControl${hash.toUpperCase()}`; + const existing = stack.node.tryFindChild(id); + if (existing) { + return existing as OriginAccessControl; + } + return new OriginAccessControl(stack, id, props); + } + + private static assignDefaultValues(props: OriginAccessControlProps): OriginAccessControlProps { + const ret = { ...props }; + ret.signingBehavior = ret.signingBehavior ?? OriginAccessControlSigningBehavior.ALWAYS; + ret.signingProtocol = ret.signingProtocol ?? OriginAccessControlSigningProtocol.SIGV4; + return ret; + } + + /** + * The Origin Access Control Id + * + * @attribute + */ + public readonly originAccessControlId: string; + + /** + * CDK L1 resource + */ + private readonly resource: CfnOriginAccessControl; + + constructor(scope: Construct, id: string, props: OriginAccessControlProps) { + super(scope, id, { physicalName: props.originAccessControlName }); + + props = OriginAccessControl.assignDefaultValues(props); + + this.resource = new CfnOriginAccessControl(this, 'Resource', { + originAccessControlConfig: { + name: props.originAccessControlName ?? cdk.Names.uniqueResourceName(this, { maxLength: 64 }), + description: props.description, + originAccessControlOriginType: props.originType, + signingBehavior: props.signingBehavior!, + signingProtocol: props.signingProtocol!, + }, + }); + this.originAccessControlId = this.getResourceNameAttribute(this.resource.ref); + } +} diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index ca08aa477f018..765c72885989d 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -9,6 +9,7 @@ import { HttpVersion, IDistribution, LambdaEdgeEventType, OriginProtocolPolicy, import { FunctionAssociation } from './function'; import { GeoRestriction } from './geo-restriction'; import { IKeyGroup } from './key-group'; +import { IOriginAccessControl, OriginAccessControl } from './origin-access-control'; import { IOriginAccessIdentity } from './origin-access-identity'; import { formatDistributionArn } from './private/utils'; @@ -304,10 +305,26 @@ export interface S3OriginConfig { */ readonly s3BucketSource: s3.IBucket; + /** + * An optional "origin access control" (OAC) that this CloudFront distrubion will use to sign S3 requests. + * This replaces the legacy "origin access identity" authentication method. You cannot specify both this + * property and also `originAccessIdentity`. + * + * If this property is set to `true`, a default OAC resource will be added to the stack. + * + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html + * + * @default - No origin access control, falling back to origin access identity configuration + */ + readonly originAccessControl?: IOriginAccessControl | true; + /** * The optional Origin Access Identity of the origin identity cloudfront will use when calling your s3 bucket. + * You should prefer `originAccessControl` for all new use cases, this exists for backwards compatibility. + * + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html * - * @default No Origin Access Identity which requires the S3 bucket to be public accessible + * @default - No Origin Access Identity which requires the S3 bucket to be public accessible */ readonly originAccessIdentity?: IOriginAccessIdentity; @@ -752,12 +769,14 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu public readonly domainName: string; public readonly distributionDomainName: string; public readonly distributionId: string; + public readonly distributionArn: string; constructor() { super(scope, id); this.domainName = attrs.domainName; this.distributionDomainName = attrs.domainName; this.distributionId = attrs.distributionId; + this.distributionArn = formatDistributionArn(this); } public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { @@ -796,6 +815,11 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu */ public readonly distributionId: string; + /** + * The distribution ARN for this distribution. + */ + public readonly distributionArn: string; + /** * Maps our methods to the string arrays they are */ @@ -989,6 +1013,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu this.domainName = distribution.attrDomainName; this.distributionDomainName = distribution.attrDomainName; this.distributionId = distribution.ref; + this.distributionArn = formatDistributionArn(this); } /** @@ -1120,6 +1145,12 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu if (originConfig.s3OriginSource) { // first case for backwards compatibility if (originConfig.s3OriginSource.originAccessIdentity) { + if (originConfig.s3OriginSource.originAccessControl) { + throw new Error( + 'The same origin cannot specify both originAccessControl and originAccessIdentity', + ); + } + // grant CloudFront OriginAccessIdentity read access to S3 bucket // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. // Only GetObject is needed to retrieve objects for the distribution. @@ -1149,6 +1180,11 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu throw new Error('connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); } + let originAccessControl = originConfig.s3OriginSource?.originAccessControl; + if (originAccessControl === true) { + originAccessControl = OriginAccessControl.fromS3Defaults(this); + } + const originProperty: CfnDistribution.OriginProperty = { id: originId, domainName: originConfig.s3OriginSource @@ -1158,6 +1194,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu originCustomHeaders: originHeaders.length > 0 ? originHeaders : undefined, s3OriginConfig, + originAccessControlId: originAccessControl?.originAccessControlId, originShield: this.toOriginShieldProperty(originConfig), customOriginConfig: originConfig.customOriginSource ? { diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.assets.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.assets.json new file mode 100644 index 0000000000000..a431cea19013e --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.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.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.template.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.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.cloudfront-s3-oac-l2.js.snapshot/cdk.out b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.assets.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.assets.json new file mode 100644 index 0000000000000..a0524cadc48aa --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "20078edfd7667744ee6ac099a0ef64f0fbb29b904e809322a43939a7c92deca0": { + "source": { + "path": "integ-cloudfront-s3-oac-l2.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "20078edfd7667744ee6ac099a0ef64f0fbb29b904e809322a43939a7c92deca0.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.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.template.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.template.json new file mode 100644 index 0000000000000..d697a79fca14b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ-cloudfront-s3-oac-l2.template.json @@ -0,0 +1,218 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "OACL2C7CC1987": { + "Type": "AWS::CloudFront::OriginAccessControl", + "Properties": { + "OriginAccessControlConfig": { + "Name": "integcloudfronts3oacl2OACL20729B516", + "OriginAccessControlOriginType": "s3", + "SigningBehavior": "always", + "SigningProtocol": "sigv4" + } + } + }, + "DistributionCFDistribution882A7313": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "DefaultCacheBehavior": { + "AllowedMethods": [ + "GET", + "HEAD" + ], + "CachedMethods": [ + "GET", + "HEAD" + ], + "Compress": true, + "ForwardedValues": { + "Cookies": { + "Forward": "none" + }, + "QueryString": false + }, + "TargetOriginId": "origin1", + "ViewerProtocolPolicy": "redirect-to-https" + }, + "DefaultRootObject": "index.html", + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "origin1", + "OriginAccessControlId": { + "Ref": "OACL2C7CC1987" + }, + "S3OriginConfig": {} + } + ], + "PriceClass": "PriceClass_100", + "ViewerCertificate": { + "CloudFrontDefaultCertificate": true + } + } + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28": { + "Type": "AWS::CloudFront::OriginAccessControl", + "Properties": { + "OriginAccessControlConfig": { + "Name": "integcloudfronts3oacl2OriginEFE0CA7DB170D0C7D8E8DC4943CF506089EA", + "OriginAccessControlOriginType": "s3", + "SigningBehavior": "always", + "SigningProtocol": "sigv4" + } + } + }, + "Distribution2CFDistribution297A8304": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "DefaultCacheBehavior": { + "AllowedMethods": [ + "GET", + "HEAD" + ], + "CachedMethods": [ + "GET", + "HEAD" + ], + "Compress": true, + "ForwardedValues": { + "Cookies": { + "Forward": "none" + }, + "QueryString": false + }, + "TargetOriginId": "origin1", + "ViewerProtocolPolicy": "redirect-to-https" + }, + "DefaultRootObject": "index.html", + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "origin1", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + } + ], + "PriceClass": "PriceClass_100", + "ViewerCertificate": { + "CloudFrontDefaultCertificate": true + } + } + } + }, + "Distribution3CFDistribution15BC87C4": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "DefaultCacheBehavior": { + "AllowedMethods": [ + "GET", + "HEAD" + ], + "CachedMethods": [ + "GET", + "HEAD" + ], + "Compress": true, + "ForwardedValues": { + "Cookies": { + "Forward": "none" + }, + "QueryString": false + }, + "TargetOriginId": "origin1", + "ViewerProtocolPolicy": "redirect-to-https" + }, + "DefaultRootObject": "index.html", + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "origin1", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + } + ], + "PriceClass": "PriceClass_100", + "ViewerCertificate": { + "CloudFrontDefaultCertificate": true + } + } + } + } + }, + "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.cloudfront-s3-oac-l2.js.snapshot/integ.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ.json new file mode 100644 index 0000000000000..a072c6ae24b6f --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "31.0.0", + "testCases": { + "S3OriginAccessControlL2/DefaultTest": { + "stacks": [ + "integ-cloudfront-s3-oac-l2" + ], + "assertionStack": "S3OriginAccessControlL2/DefaultTest/DeployAssert", + "assertionStackName": "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/manifest.json new file mode 100644 index 0000000000000..509bee31bd12d --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/manifest.json @@ -0,0 +1,141 @@ +{ + "version": "31.0.0", + "artifacts": { + "integ-cloudfront-s3-oac-l2.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-cloudfront-s3-oac-l2.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-cloudfront-s3-oac-l2": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-cloudfront-s3-oac-l2.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}/20078edfd7667744ee6ac099a0ef64f0fbb29b904e809322a43939a7c92deca0.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-cloudfront-s3-oac-l2.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-cloudfront-s3-oac-l2.assets" + ], + "metadata": { + "/integ-cloudfront-s3-oac-l2/Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Bucket83908E77" + } + ], + "/integ-cloudfront-s3-oac-l2/OACL2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OACL2C7CC1987" + } + ], + "/integ-cloudfront-s3-oac-l2/Distribution/CFDistribution": [ + { + "type": "aws:cdk:logicalId", + "data": "DistributionCFDistribution882A7313" + } + ], + "/integ-cloudfront-s3-oac-l2/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + ], + "/integ-cloudfront-s3-oac-l2/Distribution2/CFDistribution": [ + { + "type": "aws:cdk:logicalId", + "data": "Distribution2CFDistribution297A8304" + } + ], + "/integ-cloudfront-s3-oac-l2/Distribution3/CFDistribution": [ + { + "type": "aws:cdk:logicalId", + "data": "Distribution3CFDistribution15BC87C4" + } + ], + "/integ-cloudfront-s3-oac-l2/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-cloudfront-s3-oac-l2/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-cloudfront-s3-oac-l2" + }, + "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.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": [ + "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.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": [ + "S3OriginAccessControlL2DefaultTestDeployAssertEF946D96.assets" + ], + "metadata": { + "/S3OriginAccessControlL2/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/S3OriginAccessControlL2/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "S3OriginAccessControlL2/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/tree.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/tree.json new file mode 100644 index 0000000000000..b431c945f7a29 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.js.snapshot/tree.json @@ -0,0 +1,388 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integ-cloudfront-s3-oac-l2": { + "id": "integ-cloudfront-s3-oac-l2", + "path": "integ-cloudfront-s3-oac-l2", + "children": { + "Bucket": { + "id": "Bucket", + "path": "integ-cloudfront-s3-oac-l2/Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-cloudfront-s3-oac-l2/Bucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "OACL2": { + "id": "OACL2", + "path": "integ-cloudfront-s3-oac-l2/OACL2", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-cloudfront-s3-oac-l2/OACL2/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", + "aws:cdk:cloudformation:props": { + "originAccessControlConfig": { + "name": "integcloudfronts3oacl2OACL20729B516", + "originAccessControlOriginType": "s3", + "signingBehavior": "always", + "signingProtocol": "sigv4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.OriginAccessControl", + "version": "0.0.0" + } + }, + "Distribution": { + "id": "Distribution", + "path": "integ-cloudfront-s3-oac-l2/Distribution", + "children": { + "CFDistribution": { + "id": "CFDistribution", + "path": "integ-cloudfront-s3-oac-l2/Distribution/CFDistribution", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "defaultRootObject": "index.html", + "httpVersion": "http2", + "priceClass": "PriceClass_100", + "ipv6Enabled": true, + "origins": [ + { + "id": "origin1", + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OACL2C7CC1987" + }, + "connectionAttempts": 3, + "connectionTimeout": 10 + } + ], + "defaultCacheBehavior": { + "allowedMethods": [ + "GET", + "HEAD" + ], + "cachedMethods": [ + "GET", + "HEAD" + ], + "compress": true, + "forwardedValues": { + "queryString": false, + "cookies": { + "forward": "none" + } + }, + "targetOriginId": "origin1", + "viewerProtocolPolicy": "redirect-to-https" + }, + "viewerCertificate": { + "cloudFrontDefaultCertificate": true + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnDistribution", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CloudFrontWebDistribution", + "version": "0.0.0" + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF": { + "id": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "path": "integ-cloudfront-s3-oac-l2/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-cloudfront-s3-oac-l2/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", + "aws:cdk:cloudformation:props": { + "originAccessControlConfig": { + "name": "integcloudfronts3oacl2OriginEFE0CA7DB170D0C7D8E8DC4943CF506089EA", + "originAccessControlOriginType": "s3", + "signingBehavior": "always", + "signingProtocol": "sigv4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.OriginAccessControl", + "version": "0.0.0" + } + }, + "Distribution2": { + "id": "Distribution2", + "path": "integ-cloudfront-s3-oac-l2/Distribution2", + "children": { + "CFDistribution": { + "id": "CFDistribution", + "path": "integ-cloudfront-s3-oac-l2/Distribution2/CFDistribution", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "defaultRootObject": "index.html", + "httpVersion": "http2", + "priceClass": "PriceClass_100", + "ipv6Enabled": true, + "origins": [ + { + "id": "origin1", + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "connectionAttempts": 3, + "connectionTimeout": 10 + } + ], + "defaultCacheBehavior": { + "allowedMethods": [ + "GET", + "HEAD" + ], + "cachedMethods": [ + "GET", + "HEAD" + ], + "compress": true, + "forwardedValues": { + "queryString": false, + "cookies": { + "forward": "none" + } + }, + "targetOriginId": "origin1", + "viewerProtocolPolicy": "redirect-to-https" + }, + "viewerCertificate": { + "cloudFrontDefaultCertificate": true + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnDistribution", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CloudFrontWebDistribution", + "version": "0.0.0" + } + }, + "Distribution3": { + "id": "Distribution3", + "path": "integ-cloudfront-s3-oac-l2/Distribution3", + "children": { + "CFDistribution": { + "id": "CFDistribution", + "path": "integ-cloudfront-s3-oac-l2/Distribution3/CFDistribution", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "defaultRootObject": "index.html", + "httpVersion": "http2", + "priceClass": "PriceClass_100", + "ipv6Enabled": true, + "origins": [ + { + "id": "origin1", + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "connectionAttempts": 3, + "connectionTimeout": 10 + } + ], + "defaultCacheBehavior": { + "allowedMethods": [ + "GET", + "HEAD" + ], + "cachedMethods": [ + "GET", + "HEAD" + ], + "compress": true, + "forwardedValues": { + "queryString": false, + "cookies": { + "forward": "none" + } + }, + "targetOriginId": "origin1", + "viewerProtocolPolicy": "redirect-to-https" + }, + "viewerCertificate": { + "cloudFrontDefaultCertificate": true + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnDistribution", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CloudFrontWebDistribution", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-cloudfront-s3-oac-l2/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-cloudfront-s3-oac-l2/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "S3OriginAccessControlL2": { + "id": "S3OriginAccessControlL2", + "path": "S3OriginAccessControlL2", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "S3OriginAccessControlL2/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "S3OriginAccessControlL2/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "S3OriginAccessControlL2/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "S3OriginAccessControlL2/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "S3OriginAccessControlL2/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "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" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "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.cloudfront-s3-oac-l2.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.ts new file mode 100644 index 0000000000000..65cf0ab53c760 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac-l2.ts @@ -0,0 +1,49 @@ +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; +import * as cloudfront from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integ-cloudfront-s3-oac-l2'); + +const bucket = new s3.Bucket(stack, 'Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY }); + +const oac = new cloudfront.OriginAccessControl(stack, 'OACL2', { + originType: cloudfront.OriginAccessControlOriginType.S3, +}); + +new cloudfront.CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + s3OriginSource: { + s3BucketSource: bucket, + originAccessControl: oac, + }, + }], +}); + +new cloudfront.CloudFrontWebDistribution(stack, 'Distribution2', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + s3OriginSource: { + s3BucketSource: bucket, + originAccessControl: true, + }, + }], +}); + +new cloudfront.CloudFrontWebDistribution(stack, 'Distribution3', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + s3OriginSource: { + s3BucketSource: bucket, + originAccessControl: cloudfront.OriginAccessControl.fromS3Defaults(stack), + }, + }], +}); + +new IntegTest(app, 'S3OriginAccessControlL2', { + testCases: [stack], +}); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.assets.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.assets.json new file mode 100644 index 0000000000000..db0cb8d4eab63 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.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.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.template.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.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.cloudfront-s3-oac.js.snapshot/cdk.out b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.assets.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.assets.json new file mode 100644 index 0000000000000..2ec9b7ebc04b3 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "7a6a66f71ec422e3c5731fa2b2e351c1e1ddc742ca1faa36ffa0bf5dc3eb0577": { + "source": { + "path": "integ-cloudfront-s3-oac.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "7a6a66f71ec422e3c5731fa2b2e351c1e1ddc742ca1faa36ffa0bf5dc3eb0577.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.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.template.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.template.json new file mode 100644 index 0000000000000..d2e01c93e4ed9 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ-cloudfront-s3-oac.template.json @@ -0,0 +1,105 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "OAC": { + "Type": "AWS::CloudFront::OriginAccessControl", + "Properties": { + "OriginAccessControlConfig": { + "Name": "OACId", + "OriginAccessControlOriginType": "s3", + "SigningBehavior": "always", + "SigningProtocol": "sigv4" + } + } + }, + "DistributionCFDistribution882A7313": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "DefaultCacheBehavior": { + "AllowedMethods": [ + "GET", + "HEAD" + ], + "CachedMethods": [ + "GET", + "HEAD" + ], + "Compress": true, + "ForwardedValues": { + "Cookies": { + "Forward": "none" + }, + "QueryString": false + }, + "TargetOriginId": "origin1", + "ViewerProtocolPolicy": "redirect-to-https" + }, + "DefaultRootObject": "index.html", + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "origin1", + "OriginAccessControlId": { + "Ref": "OAC" + }, + "S3OriginConfig": {} + } + ], + "PriceClass": "PriceClass_100", + "ViewerCertificate": { + "CloudFrontDefaultCertificate": true + } + } + } + } + }, + "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.cloudfront-s3-oac.js.snapshot/integ.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ.json new file mode 100644 index 0000000000000..8d1ef951d7dc9 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "31.0.0", + "testCases": { + "S3OriginAccessControl/DefaultTest": { + "stacks": [ + "integ-cloudfront-s3-oac" + ], + "assertionStack": "S3OriginAccessControl/DefaultTest/DeployAssert", + "assertionStackName": "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/manifest.json new file mode 100644 index 0000000000000..aa7b23fea1dee --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/manifest.json @@ -0,0 +1,123 @@ +{ + "version": "31.0.0", + "artifacts": { + "integ-cloudfront-s3-oac.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-cloudfront-s3-oac.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-cloudfront-s3-oac": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-cloudfront-s3-oac.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}/7a6a66f71ec422e3c5731fa2b2e351c1e1ddc742ca1faa36ffa0bf5dc3eb0577.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-cloudfront-s3-oac.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-cloudfront-s3-oac.assets" + ], + "metadata": { + "/integ-cloudfront-s3-oac/Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Bucket83908E77" + } + ], + "/integ-cloudfront-s3-oac/OAC": [ + { + "type": "aws:cdk:logicalId", + "data": "OAC" + } + ], + "/integ-cloudfront-s3-oac/Distribution/CFDistribution": [ + { + "type": "aws:cdk:logicalId", + "data": "DistributionCFDistribution882A7313" + } + ], + "/integ-cloudfront-s3-oac/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-cloudfront-s3-oac/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-cloudfront-s3-oac" + }, + "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.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": [ + "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.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": [ + "S3OriginAccessControlDefaultTestDeployAssertFF6C26DC.assets" + ], + "metadata": { + "/S3OriginAccessControl/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/S3OriginAccessControl/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "S3OriginAccessControl/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/tree.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/tree.json new file mode 100644 index 0000000000000..e1c45e818ee5f --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.js.snapshot/tree.json @@ -0,0 +1,219 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integ-cloudfront-s3-oac": { + "id": "integ-cloudfront-s3-oac", + "path": "integ-cloudfront-s3-oac", + "children": { + "Bucket": { + "id": "Bucket", + "path": "integ-cloudfront-s3-oac/Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-cloudfront-s3-oac/Bucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "OAC": { + "id": "OAC", + "path": "integ-cloudfront-s3-oac/OAC", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", + "aws:cdk:cloudformation:props": { + "originAccessControlConfig": { + "name": "OACId", + "originAccessControlOriginType": "s3", + "signingBehavior": "always", + "signingProtocol": "sigv4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", + "version": "0.0.0" + } + }, + "OACImport": { + "id": "OACImport", + "path": "integ-cloudfront-s3-oac/OACImport", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Distribution": { + "id": "Distribution", + "path": "integ-cloudfront-s3-oac/Distribution", + "children": { + "CFDistribution": { + "id": "CFDistribution", + "path": "integ-cloudfront-s3-oac/Distribution/CFDistribution", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "defaultRootObject": "index.html", + "httpVersion": "http2", + "priceClass": "PriceClass_100", + "ipv6Enabled": true, + "origins": [ + { + "id": "origin1", + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OAC" + }, + "connectionAttempts": 3, + "connectionTimeout": 10 + } + ], + "defaultCacheBehavior": { + "allowedMethods": [ + "GET", + "HEAD" + ], + "cachedMethods": [ + "GET", + "HEAD" + ], + "compress": true, + "forwardedValues": { + "queryString": false, + "cookies": { + "forward": "none" + } + }, + "targetOriginId": "origin1", + "viewerProtocolPolicy": "redirect-to-https" + }, + "viewerCertificate": { + "cloudFrontDefaultCertificate": true + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnDistribution", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CloudFrontWebDistribution", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-cloudfront-s3-oac/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-cloudfront-s3-oac/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "S3OriginAccessControl": { + "id": "S3OriginAccessControl", + "path": "S3OriginAccessControl", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "S3OriginAccessControl/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "S3OriginAccessControl/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "S3OriginAccessControl/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "S3OriginAccessControl/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "S3OriginAccessControl/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "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" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "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.cloudfront-s3-oac.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.ts new file mode 100644 index 0000000000000..5ddd4b8e6be4b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3-oac.ts @@ -0,0 +1,40 @@ +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; +import * as cloudfront from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integ-cloudfront-s3-oac'); + +const bucket = new s3.Bucket(stack, 'Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY }); + +const oac = new cloudfront.CfnOriginAccessControl(stack, 'OAC', { + originAccessControlConfig: { + name: 'OACId', + originAccessControlOriginType: 's3', + signingBehavior: 'always', + signingProtocol: 'sigv4', + }, +}); + +const oacImport = cloudfront.OriginAccessControl.fromOriginAccessControlId( + stack, + 'OACImport', + oac.ref, +); + +new cloudfront.CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + s3OriginSource: { + s3BucketSource: bucket, + originAccessControl: oacImport, + }, + }], +}); + +new IntegTest(app, 'S3OriginAccessControl', { + testCases: [stack], +}); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront/test/oac.test.ts b/packages/@aws-cdk/aws-cloudfront/test/oac.test.ts new file mode 100644 index 0000000000000..be5045a1d5587 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/oac.test.ts @@ -0,0 +1,166 @@ +import { Template } from '@aws-cdk/assertions'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { OriginAccessControl, OriginAccessControlOriginType, OriginAccessControlSigningBehavior } from '../lib'; + +describe('Origin Access Control', () => { + test('With required origin types', () => { + const stack = new cdk.Stack(); + + new OriginAccessControl(stack, 'OACMediaStore', { + originType: OriginAccessControlOriginType.MEDIASTORE, + }); + + new OriginAccessControl(stack, 'OACS3', { + originType: OriginAccessControlOriginType.S3, + }); + + const tmpl = Template.fromStack(stack); + tmpl.resourceCountIs('AWS::CloudFront::OriginAccessControl', 2); + tmpl.templateMatches( + { + Resources: { + OACMediaStoreCD88D134: { + Type: 'AWS::CloudFront::OriginAccessControl', + Properties: { + OriginAccessControlConfig: { + OriginAccessControlOriginType: 'mediastore', + SigningBehavior: 'always', + SigningProtocol: 'sigv4', + }, + }, + }, + OACS35438DEEA: { + Type: 'AWS::CloudFront::OriginAccessControl', + Properties: { + OriginAccessControlConfig: { + OriginAccessControlOriginType: 's3', + SigningBehavior: 'always', + SigningProtocol: 'sigv4', + }, + }, + }, + }, + }, + ); + }); + + test('With provided OAC name', () => { + const stack = new cdk.Stack(); + + new OriginAccessControl(stack, 'OACS3', { + originAccessControlName: 'OACPhysicalId', + originType: OriginAccessControlOriginType.S3, + }); + + const tmpl = Template.fromStack(stack); + tmpl.resourceCountIs('AWS::CloudFront::OriginAccessControl', 1); + tmpl.templateMatches( + { + Resources: { + OACS35438DEEA: { + Type: 'AWS::CloudFront::OriginAccessControl', + Properties: { + OriginAccessControlConfig: { + Name: 'OACPhysicalId', + }, + }, + }, + }, + }, + ); + }); + + test('Default stack singletons', () => { + const stack = new cdk.Stack(); + const nested = new Construct(stack, 'Construct'); + + OriginAccessControl.fromS3Defaults(stack); + OriginAccessControl.fromS3Defaults(stack); + OriginAccessControl.fromMediaStoreDefaults(stack); + OriginAccessControl.fromMediaStoreDefaults(nested); + OriginAccessControl.fromS3Defaults(nested); + OriginAccessControl.fromMediaStoreDefaults(nested); + + const tmpl = Template.fromStack(stack); + + tmpl.resourceCountIs('AWS::CloudFront::OriginAccessControl', 2); + tmpl.templateMatches( + { + Resources: { + OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28: { + Type: 'AWS::CloudFront::OriginAccessControl', + Properties: { + OriginAccessControlConfig: { + OriginAccessControlOriginType: 's3', + SigningBehavior: 'always', + SigningProtocol: 'sigv4', + }, + }, + }, + OriginAccessControl07ED4DB176D4FB972C6FA0038059996CB0D48653: { + Type: 'AWS::CloudFront::OriginAccessControl', + Properties: { + OriginAccessControlConfig: { + OriginAccessControlOriginType: 'mediastore', + SigningBehavior: 'always', + SigningProtocol: 'sigv4', + }, + }, + }, + }, + }, + ); + }); + + test('Default stack singletons with behavior overrides', () => { + const stack = new cdk.Stack(); + + OriginAccessControl.fromS3Defaults(stack, undefined, undefined); + OriginAccessControl.fromS3Defaults(stack, undefined, OriginAccessControlSigningBehavior.ALWAYS); + OriginAccessControl.fromS3Defaults(stack, undefined, OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromS3Defaults(stack, undefined, OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromS3Defaults(stack, undefined, OriginAccessControlSigningBehavior.NO_OVERRIDE); + OriginAccessControl.fromS3Defaults(stack, undefined, OriginAccessControlSigningBehavior.NO_OVERRIDE); + + OriginAccessControl.fromMediaStoreDefaults(stack, undefined, undefined); + OriginAccessControl.fromMediaStoreDefaults(stack, undefined, OriginAccessControlSigningBehavior.ALWAYS); + OriginAccessControl.fromMediaStoreDefaults(stack, undefined, OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromMediaStoreDefaults(stack, undefined, OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromMediaStoreDefaults(stack, undefined, OriginAccessControlSigningBehavior.NO_OVERRIDE); + OriginAccessControl.fromMediaStoreDefaults(stack, undefined, OriginAccessControlSigningBehavior.NO_OVERRIDE); + + const tmpl = Template.fromStack(stack); + tmpl.resourceCountIs('AWS::CloudFront::OriginAccessControl', 6); + for (const val of ['always', 'never', 'no-override']) { + const props = { OriginAccessControlConfig: { SigningBehavior: val } }; + tmpl.resourcePropertiesCountIs('AWS::CloudFront::OriginAccessControl', props, 2); + } + }); + + test('Defaults with explicit construct ids', () => { + const stack = new cdk.Stack(); + + OriginAccessControl.fromS3Defaults(stack, 'OACS1', undefined); + OriginAccessControl.fromS3Defaults(stack, 'OACS2', OriginAccessControlSigningBehavior.ALWAYS); + OriginAccessControl.fromS3Defaults(stack, 'OACS3', OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromS3Defaults(stack, 'OACS4', OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromS3Defaults(stack, 'OACS5', OriginAccessControlSigningBehavior.NO_OVERRIDE); + OriginAccessControl.fromS3Defaults(stack, 'OACS6', OriginAccessControlSigningBehavior.NO_OVERRIDE); + + OriginAccessControl.fromMediaStoreDefaults(stack, 'OACM1', undefined); + OriginAccessControl.fromMediaStoreDefaults(stack, 'OACM2', OriginAccessControlSigningBehavior.ALWAYS); + OriginAccessControl.fromMediaStoreDefaults(stack, 'OACM3', OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromMediaStoreDefaults(stack, 'OACM4', OriginAccessControlSigningBehavior.NEVER); + OriginAccessControl.fromMediaStoreDefaults(stack, 'OACM5', OriginAccessControlSigningBehavior.NO_OVERRIDE); + OriginAccessControl.fromMediaStoreDefaults(stack, 'OACM6', OriginAccessControlSigningBehavior.NO_OVERRIDE); + + const tmpl = Template.fromStack(stack); + tmpl.resourceCountIs('AWS::CloudFront::OriginAccessControl', 12); + for (const val of ['always', 'never', 'no-override']) { + const props = { OriginAccessControlConfig: { SigningBehavior: val } }; + tmpl.resourcePropertiesCountIs('AWS::CloudFront::OriginAccessControl', props, 4); + } + }); +}); + 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 e5b65d12915ed..e6e918a78bc3f 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -14,6 +14,8 @@ import { GeoRestriction, KeyGroup, LambdaEdgeEventType, + OriginAccessControl, + OriginAccessControlOriginType, OriginAccessIdentity, PublicKey, SecurityPolicyProtocol, @@ -406,10 +408,58 @@ added the ellipsis so a user would know there was more to r...`, }], }, }); + }); + + test('distribution with bucket and explicit OAC', () => { + const stack = new cdk.Stack(); + const s3BucketSource = new s3.Bucket(stack, 'Bucket'); + const oac = new OriginAccessControl(stack, 'OAC', { + originType: OriginAccessControlOriginType.S3, + }); + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + originConfigs: [{ + s3OriginSource: { s3BucketSource, originAccessControl: oac }, + behaviors: [{ isDefaultBehavior: true }], + }], + }); + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { + DistributionConfig: { + Origins: [ + { + Id: 'origin1', + OriginAccessControlId: Match.anyValue(), + S3OriginConfig: { OriginAccessIdentity: Match.absent() }, + }, + ], + }, + }); }); + test('distribution with bucket and default OAC', () => { + const stack = new cdk.Stack(); + const s3BucketSource = new s3.Bucket(stack, 'Bucket'); + + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + originConfigs: [{ + s3OriginSource: { s3BucketSource, originAccessControl: true }, + behaviors: [{ isDefaultBehavior: true }], + }], + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', { + DistributionConfig: { + Origins: [ + { + Id: 'origin1', + OriginAccessControlId: Match.anyValue(), + S3OriginConfig: { OriginAccessIdentity: Match.absent() }, + }, + ], + }, + }); + }); testDeprecated('distribution with trusted signers on default distribution', () => { const stack = new cdk.Stack(); From a88901f18aa509509b6a227a19cbe2d69a36d90f Mon Sep 17 00:00:00 2001 From: Henry Goffin Date: Thu, 30 Mar 2023 08:34:43 +0000 Subject: [PATCH 2/7] modify READMEs --- .../@aws-cdk/aws-cloudfront-origins/README.md | 109 +++++++++++------- packages/@aws-cdk/aws-cloudfront/README.md | 76 ------------ 2 files changed, 69 insertions(+), 116 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront-origins/README.md b/packages/@aws-cdk/aws-cloudfront-origins/README.md index e58af3c142212..4262245ec7c98 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/README.md +++ b/packages/@aws-cdk/aws-cloudfront-origins/README.md @@ -12,40 +12,65 @@ This library contains convenience methods for defining origins for a CloudFront distribution. You can use this library to create origins from S3 buckets, Elastic Load Balancing v2 load balancers, or any other domain name. -## S3 Bucket -An S3 bucket can be added as an origin. If the bucket is configured as a website endpoint, the distribution can use S3 redirects and S3 custom error -documents. +## From any generic HTTP endpoint + +Any public HTTP or HTTPS endpoint can be used as an origin, as long as it has a static domain name. ```ts -const myBucket = new s3.Bucket(this, 'myBucket'); +// Creates a distribution from an HTTP endpoint new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.S3Origin(myBucket) }, + defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, }); ``` -The above will treat the bucket differently based on if `IBucket.isWebsite` is set or not. If the bucket is configured as a website, the bucket is -treated as an HTTP origin, and the built-in S3 redirects and error pages can be used. Otherwise, the bucket is handled as a bucket origin and -CloudFront's redirect and error handling will be used. In the latter case, the Origin will create an origin access identity and grant it access to the -underlying bucket. This can be used in conjunction with a bucket that is not public to require that your users access your content using CloudFront -URLs and not S3 URLs directly. Alternatively, a custom origin access identity can be passed to the S3 origin in the properties. +## From an S3 Bucket with IAM access controls -### Adding Custom Headers +Any S3 bucket can be used as an origin. If the bucket is not configured for public website hosting, the distribution +will access bucket contents through the standard S3 `GetObject` API. -You can configure CloudFront to add custom headers to the requests that it sends to your origin. These custom headers enable you to send and gather information from your origin that you don’t get with typical viewer requests. These headers can even be customized for each origin. CloudFront supports custom headers for both for custom and Amazon S3 origins. +CloudFront supports two methods of authenticating with S3: origin access control (OAC) and origin access identity (OAI). OAI +is a legacy authentication method which will not be supported in new regions. It is strongly recommended to use OAC for all +new deployments. + +You can enable OAC by setting the `originAccessControl` property to `true`, or by explicitly supplying an `OriginAccessControl` +resource. If you leave OAC disabled, the legacy OAI method will be used by default for backwards-compatibility reasons. ```ts +// Creates a distribution from a private S3 bucket using Origin Access Control const myBucket = new s3.Bucket(this, 'myBucket'); new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.S3Origin(myBucket, { - customHeaders: { - Foo: 'bar', - }, - })}, + defaultBehavior: { origin: new origins.S3Origin(myBucket, { originAccessControl: true }) }, +}); +``` + +The `S3Origin` construct will automatically adjust the bucket resource policy to grant necessary `s3:GetObject` permissions. +When using OAC, any failure when adjusting permissions will result in an error message. If you cannot resolve the error, you +can set `autoResourcePolicy: false` to allow deployment and then manually adjust resource policies after deployment. + +When using OAI, some types of failures when adjusting permissions will be silently ignored. You should verify that your +distribution is properly serving origin content after deployment, and then adjust resource policies if necessary. + +See [Restricting access to an Amazon S3 origin](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html) for more details about OAC, OAI, and resource policies. + +## From a website-enabled S3 Bucket with public read access + +A website-enabled S3 bucket can also be used as an origin. The distribution will access the bucket through +the public website endpoint and honor any existing S3 configuration for index documents, error documents, +and redirections. + +```ts +// Creates a distribution from a public website-enabled S3 bucket +const publicWebBucket = new s3.Bucket(this, 'myWebsiteBucket', { + publicReadAccess: true, + websiteIndexDocument: 'index.html', +}); +new cloudfront.Distribution(this, 'myDist', { + defaultBehavior: { origin: new origins.S3Origin(publicWebBucket) }, }); ``` -## ELBv2 Load Balancer +## From an ELBv2 Load Balancer An Elastic Load Balancing (ELB) v2 load balancer may be used as an origin. In order for a load balancer to serve as an origin, it must be publicly accessible (`internetFacing` is true). Both Application and Network load balancers are supported. @@ -85,19 +110,28 @@ Note that the `readTimeout` and `keepaliveTimeout` properties can extend their v quota has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. Consider that this value is still limited to a maximum value of 180 seconds, which is a hard limit for that quota. -## From an HTTP endpoint +## From an API Gateway REST API -Origins can also be created from any other HTTP endpoint, given the domain name, and optionally, other origin properties. +Origins can be created from an API Gateway REST API. It is recommended to use a +[regional API](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-endpoint-types.html) in this case. The origin path will automatically be set as the stage name. ```ts -new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, +declare const api: apigateway.RestApi; +new cloudfront.Distribution(this, 'Distribution', { + defaultBehavior: { origin: new origins.RestApiOrigin(api) }, }); ``` -See the documentation of `@aws-cdk/aws-cloudfront` for more information. +If you want to use a different origin path, you can specify it in the `originPath` property. + +```ts +declare const api: apigateway.RestApi; +new cloudfront.Distribution(this, 'Distribution', { + defaultBehavior: { origin: new origins.RestApiOrigin(api, { originPath: '/custom-origin-path' }) }, +}); +``` -## Failover Origins (Origin Groups) +## From a failover configuration with multiple origins (Origin Groups) You can set up CloudFront with origin failover for scenarios that require high availability. To get started, you create an origin group with two origins: a primary and a secondary. @@ -110,7 +144,7 @@ const myBucket = new s3.Bucket(this, 'myBucket'); new cloudfront.Distribution(this, 'myDist', { defaultBehavior: { origin: new origins.OriginGroup({ - primaryOrigin: new origins.S3Origin(myBucket), + primaryOrigin: new origins.S3Origin(myBucket, { originAccessControl: true }), fallbackOrigin: new origins.HttpOrigin('www.example.com'), // optional, defaults to: 500, 502, 503 and 504 fallbackStatusCodes: [404], @@ -119,23 +153,18 @@ new cloudfront.Distribution(this, 'myDist', { }); ``` -## From an API Gateway REST API - -Origins can be created from an API Gateway REST API. It is recommended to use a -[regional API](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-endpoint-types.html) in this case. The origin path will automatically be set as the stage name. - -```ts -declare const api: apigateway.RestApi; -new cloudfront.Distribution(this, 'Distribution', { - defaultBehavior: { origin: new origins.RestApiOrigin(api) }, -}); -``` +## Adding Custom Headers -If you want to use a different origin path, you can specify it in the `originPath` property. +You can configure CloudFront to add custom headers to the requests that it sends to your origin. These custom headers enable you to send and gather information from your origin that you don’t get with typical viewer requests. These headers can even be customized for each origin. CloudFront supports custom headers for both for custom and Amazon S3 origins. ```ts -declare const api: apigateway.RestApi; -new cloudfront.Distribution(this, 'Distribution', { - defaultBehavior: { origin: new origins.RestApiOrigin(api, { originPath: '/custom-origin-path' }) }, +const myBucket = new s3.Bucket(this, 'myBucket'); +new cloudfront.Distribution(this, 'myDist', { + defaultBehavior: { origin: new origins.S3Origin(myBucket, { + orginAccessControl: true, + customHeaders: { + Foo: 'bar', + }, + })}, }); ``` diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index 01544e7d6ea7f..391a6cc97ebdf 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -33,82 +33,6 @@ Additional behaviors may be specified for an origin with a given URL path patter controlling which HTTP methods to support, whether to require users to use HTTPS, and what query strings or cookies to forward to your origin, among other settings. -#### From any generic HTTP endpoint - -Any public HTTP or HTTPS endpoint can be used as an origin, as long as it has a static domain name. - -```ts -// Creates a distribution from an HTTP endpoint -new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, -}); -``` - -#### From an S3 Bucket with IAM access controls - -Any S3 bucket can be used as an origin. If the bucket is not configured for public website hosting, the distribution -will access bucket contents through the standard S3 `GetObject` API. - -CloudFront supports two methods of authenticating with S3: origin access control (OAC) and origin access identity (OAI). OAI -is a legacy authentication method which will not be supported in new regions. It is strongly recommended to use OAC for all -new deployments. - -You can enable OAC by setting the `originAccessControl` property to `true`, or by explicitly supplying an `OriginAccessControl` -resource. If you leave OAC disabled, the legacy OAI method will be used by default for backwards-compatibility reasons. - -```ts -// Creates a distribution from a private S3 bucket using Origin Access Control -const myBucket = new s3.Bucket(this, 'myBucket'); -new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.S3Origin(myBucket, { originAccessControl: true }) }, -}); -``` - -The `S3Origin` construct will automatically adjust the bucket resource policy to grant necessary `s3:GetObject` permissions. -When using OAC, any failure when adjusting permissions will result in an error message. If you cannot resolve the error, you -can set `autoResourcePolicy: false` to allow deployment and then manually adjust resource policies after deployment. - -When using OAI, some types of failures when adjusting permissions will be silently ignored. You should verify that your -distribution is properly serving origin content after deployment, and then adjust resource policies if necessary. - -See [Restricting access to an Amazon S3 origin](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html) for more details about OAC, OAI, and resource policies. - -#### From a website-enabled S3 Bucket with public read access - -A website-enabled S3 bucket can also be used as an origin. The distribution will access the bucket through -the public website endpoint and honor any existing S3 configuration for index documents, error documents, -and redirections. - -```ts -// Creates a distribution from a public website-enabled S3 bucket -const publicWebBucket = new s3.Bucket(this, 'myWebsiteBucket', { - publicReadAccess: true, - websiteIndexDocument: 'index.html', -}); -new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.S3Origin(publicWebBucket) }, -}); -``` - -#### From an ELBv2 Load Balancer - -An Elastic Load Balancing (ELB) v2 load balancer may be used as an origin. In order for a load balancer to serve as an origin, it must be publicly -accessible (`internetFacing` is true). Both Application and Network load balancers are supported. - -```ts -// Creates a distribution from an ELBv2 load balancer -declare const vpc: ec2.Vpc; -// Create an application load balancer in a VPC. 'internetFacing' must be 'true' -// for CloudFront to access the load balancer and use it as an origin. -const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', { - vpc, - internetFacing: true, -}); -new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.LoadBalancerV2Origin(lb) }, -}); -``` - ### Domain Names and Certificates When you create a distribution, CloudFront assigns a domain name for the distribution, for example: `d111111abcdef8.cloudfront.net`; this value can From 0ca2aff66c3083e7c192466e6df2cd62ac682df9 Mon Sep 17 00:00:00 2001 From: Henry Goffin Date: Thu, 30 Mar 2023 20:19:05 +0000 Subject: [PATCH 3/7] refactor, add integration test, update README --- .../@aws-cdk/aws-cloudfront-origins/README.md | 4 +- .../aws-cloudfront-origins/lib/s3-origin.ts | 92 +- ...efaultTestDeployAssert62DBC588.assets.json | 19 + ...aultTestDeployAssert62DBC588.template.json | 36 + .../__entrypoint__.js | 147 +++ .../index.js | 78 ++ .../integ.s3-origin-oac.js.snapshot/cdk.out | 1 + .../integ.json | 13 + .../manifest.json | 237 ++++ .../s3origin-oac-1.assets.json | 32 + .../s3origin-oac-1.template.json | 617 ++++++++++ .../s3origin-oac-multistack.assets.json | 19 + .../s3origin-oac-multistack.template.json | 111 ++ .../integ.s3-origin-oac.js.snapshot/tree.json | 1035 +++++++++++++++++ .../test/integ.s3-origin-oac.ts | 67 ++ 15 files changed, 2470 insertions(+), 38 deletions(-) create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/__entrypoint__.js create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts diff --git a/packages/@aws-cdk/aws-cloudfront-origins/README.md b/packages/@aws-cdk/aws-cloudfront-origins/README.md index 4262245ec7c98..e13fd0f010740 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/README.md +++ b/packages/@aws-cdk/aws-cloudfront-origins/README.md @@ -20,7 +20,7 @@ Any public HTTP or HTTPS endpoint can be used as an origin, as long as it has a ```ts // Creates a distribution from an HTTP endpoint new cloudfront.Distribution(this, 'myDist', { - defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, + defaultBehavior: { origin: new origins.HttpOrigin('www-origin.example.com') }, }); ``` @@ -34,7 +34,7 @@ is a legacy authentication method which will not be supported in new regions. It new deployments. You can enable OAC by setting the `originAccessControl` property to `true`, or by explicitly supplying an `OriginAccessControl` -resource. If you leave OAC disabled, the legacy OAI method will be used by default for backwards-compatibility reasons. +resource. If you do not specify anything, the legacy OAI method will be used by default for backwards-compatibility reasons. ```ts // Creates a distribution from a private S3 bucket using Origin Access Control diff --git a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts index fd81dd930a6ba..3f17c9fa21485 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts @@ -1,5 +1,4 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; -import { OriginAccessControl } from '@aws-cdk/aws-cloudfront'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; @@ -49,9 +48,11 @@ export interface S3OriginProps extends cloudfront.OriginProps { * When used in a stack with a legacy OAI configuration, only a best-effort attempt will be made to set * resource policies. Any failures due to imported or cross-stack resources will be ignored. * + * `true` is a convenience alias for READ_ONLY and `false` is an alias for NONE. + * * @default S3OriginAutoResourcePolicyConfig.READ_ONLY */ - readonly autoResourcePolicy?: S3OriginAutoResourcePolicy; + readonly autoResourcePolicy?: S3OriginAutoResourcePolicy | boolean; /** * An optional "origin access control" (OAC) resource which describes how the distribution should * sign its requests for the S3 bucket origin. Can also be set to `true` to apply a default OAC. @@ -116,44 +117,63 @@ class S3BucketOrigin extends cloudfront.OriginBase { } this.originAccessControl = props.originAccessControl; this.originAccessIdentity = props.originAccessIdentity; - this.autoResourcePolicy = props.autoResourcePolicy ?? S3OriginAutoResourcePolicy.READ_ONLY; + const autopolicy = props.autoResourcePolicy ?? true; + if (autopolicy === true) { + this.autoResourcePolicy = S3OriginAutoResourcePolicy.READ_ONLY; + } else if (autopolicy === false) { + this.autoResourcePolicy = S3OriginAutoResourcePolicy.NONE; + } else { + this.autoResourcePolicy = autopolicy; + } } - public bind(scope: Construct, options: cloudfront.OriginBindOptions): cloudfront.OriginBindConfig { - if (this.originAccessControl) { - if (this.autoResourcePolicy != S3OriginAutoResourcePolicy.NONE) { - const readonly = this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_ONLY; - const dist = scope.node.scope as cloudfront.Distribution; - const lazyDistArn = cdk.Lazy.string({ produce: () => dist.distributionArn }); - const added = this.bucket.addToResourcePolicy(new iam.PolicyStatement({ - principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')], - actions: readonly ? ['s3:GetObject'] : ['s3:GetObject', 's3:PutObject'], - resources: [this.bucket.arnForObjects('*')], - conditions: { StringEquals: { 'aws:SourceArn': lazyDistArn } }, - })); - if (!added.statementAdded) { - throw new Error('S3Origin cannot edit imported buckets, try autoResourcePolicy=NONE'); - } - // Buckets work because the bucket policies are only installed after the bucket - // is created, so the bucket policy can have a dependency on the distribution - // which depends on the bucket. But KMS keys need their policy at creation time, - // and there is no way to break the circular dependency with the distribution... - // unless we write a custom resource Lambda that modifies the key policy "later"? - if (this.bucket.encryptionKey) { - throw new Error('S3Origin cannot edit KMS keys at this time, try autoResourcePolicy=NONE'); - } + private bindOAC(scope: Construct, options: cloudfront.OriginBindOptions): cloudfront.OriginBindConfig { + if (this.autoResourcePolicy != S3OriginAutoResourcePolicy.NONE) { + if (cdk.Stack.of(this.bucket) != cdk.Stack.of(scope)) { + // The bucket policy must be mangaed by the same stack as the CloudFront distribution. + // If we do not check for this, it will create a circular cross-stack dependency. + throw new Error('Cannot edit cross-stack bucket policy due to circular dependency, set autoResourcePolicy to false'); + } + const readonly = this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_ONLY; + const dist = scope.node.scope as cloudfront.Distribution; + const lazyDistArn = cdk.Lazy.string({ produce: () => dist.distributionArn }); + const added = this.bucket.addToResourcePolicy(new iam.PolicyStatement({ + principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')], + actions: readonly ? ['s3:GetObject'] : ['s3:GetObject', 's3:PutObject'], + resources: [this.bucket.arnForObjects('*')], + conditions: { StringEquals: { 'aws:SourceArn': lazyDistArn } }, + })); + if (!added.statementAdded) { + throw new Error('Cannot edit non-CDK-managed policy on imported buckets, set autoResourcePolicy to false'); } - let oac = this.originAccessControl; - if (oac === true) { - oac = OriginAccessControl.fromS3Defaults(scope); + // Buckets work because the bucket policies are only installed after the bucket + // is created, so the bucket policy can have a dependency on the distribution + // which depends on the bucket. But KMS keys need their policy at creation time, + // and there is no way to break the circular dependency with the distribution... + // unless we write a custom resource Lambda that modifies the key policy "later"? + if (this.bucket.encryptionKey) { + throw new Error('Cannot edit KMS key policy due to circular dependency, set autoResourcePolicy to false'); } - const newBindConfig = { ...super.bind(scope, options) }; - const newOriginProp = { ...newBindConfig.originProperty! }; - newOriginProp.originAccessControlId = oac.originAccessControlId; - newBindConfig.originProperty = newOriginProp; - return newBindConfig; } + let oac = this.originAccessControl ?? true; + if (oac === true) { + oac = cloudfront.OriginAccessControl.fromS3Defaults(scope); + } + // Wrap base-class results and directly inject OAC Id property + const baseConfig = super.bind(scope, options); + return { + ...baseConfig, + originProperty: { + ...baseConfig.originProperty!, + originAccessControlId: oac.originAccessControlId, + }, + }; + } + public bind(scope: Construct, options: cloudfront.OriginBindOptions): cloudfront.OriginBindConfig { + if (this.originAccessControl) { + return this.bindOAC(scope, options); + } if (!this.originAccessIdentity) { // Using a bucket from another stack creates a cyclic reference with // the bucket taking a dependency on the generated S3CanonicalUserId for the grant principal, @@ -169,9 +189,9 @@ class S3BucketOrigin extends cloudfront.OriginBase { }); } if (this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_WRITE) { - throw new Error('S3OriginAutoResourcePolicy.READ_WRITE is not supported with Origin Access Identity'); + throw new Error('S3OriginAutoResourcePolicy.READ_WRITE cannot be used with originAccessIdentity'); } - if (this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_ONLY) { + if (this.autoResourcePolicy != S3OriginAutoResourcePolicy.NONE) { // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. // Only GetObject is needed to retrieve objects for the distribution. // This also excludes KMS permissions; currently, OAI only supports SSE-S3 for buckets. diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json new file mode 100644 index 0000000000000..0e06662be879c --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.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-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.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-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/__entrypoint__.js b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/__entrypoint__.js new file mode 100644 index 0000000000000..c83ecebaaadac --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/__entrypoint__.js @@ -0,0 +1,147 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withRetries = exports.handler = exports.external = void 0; +const https = require("https"); +const url = require("url"); +// for unit tests +exports.external = { + sendHttpRequest: defaultSendHttpRequest, + log: defaultLog, + includeStackTraces: true, + userHandlerIndex: './index', +}; +const CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; +const MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; +async function handler(event, context) { + const sanitizedEvent = { ...event, ResponseURL: '...' }; + exports.external.log(JSON.stringify(sanitizedEvent, undefined, 2)); + // ignore DELETE event when the physical resource ID is the marker that + // indicates that this DELETE is a subsequent DELETE to a failed CREATE + // operation. + if (event.RequestType === 'Delete' && event.PhysicalResourceId === CREATE_FAILED_PHYSICAL_ID_MARKER) { + exports.external.log('ignoring DELETE event caused by a failed CREATE event'); + await submitResponse('SUCCESS', event); + return; + } + try { + // invoke the user handler. this is intentionally inside the try-catch to + // ensure that if there is an error it's reported as a failure to + // cloudformation (otherwise cfn waits). + // eslint-disable-next-line @typescript-eslint/no-require-imports + const userHandler = require(exports.external.userHandlerIndex).handler; + const result = await userHandler(sanitizedEvent, context); + // validate user response and create the combined event + const responseEvent = renderResponse(event, result); + // submit to cfn as success + await submitResponse('SUCCESS', responseEvent); + } + catch (e) { + const resp = { + ...event, + Reason: exports.external.includeStackTraces ? e.stack : e.message, + }; + if (!resp.PhysicalResourceId) { + // special case: if CREATE fails, which usually implies, we usually don't + // have a physical resource id. in this case, the subsequent DELETE + // operation does not have any meaning, and will likely fail as well. to + // address this, we use a marker so the provider framework can simply + // ignore the subsequent DELETE. + if (event.RequestType === 'Create') { + exports.external.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); + resp.PhysicalResourceId = CREATE_FAILED_PHYSICAL_ID_MARKER; + } + else { + // otherwise, if PhysicalResourceId is not specified, something is + // terribly wrong because all other events should have an ID. + exports.external.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(event)}`); + } + } + // this is an actual error, fail the activity altogether and exist. + await submitResponse('FAILED', resp); + } +} +exports.handler = handler; +function renderResponse(cfnRequest, handlerResponse = {}) { + // if physical ID is not returned, we have some defaults for you based + // on the request type. + const physicalResourceId = handlerResponse.PhysicalResourceId ?? cfnRequest.PhysicalResourceId ?? cfnRequest.RequestId; + // if we are in DELETE and physical ID was changed, it's an error. + if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { + throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${handlerResponse.PhysicalResourceId}" during deletion`); + } + // merge request event and result event (result prevails). + return { + ...cfnRequest, + ...handlerResponse, + PhysicalResourceId: physicalResourceId, + }; +} +async function submitResponse(status, event) { + const json = { + Status: status, + Reason: event.Reason ?? status, + StackId: event.StackId, + RequestId: event.RequestId, + PhysicalResourceId: event.PhysicalResourceId || MISSING_PHYSICAL_ID_MARKER, + LogicalResourceId: event.LogicalResourceId, + NoEcho: event.NoEcho, + Data: event.Data, + }; + exports.external.log('submit response to cloudformation', json); + const responseBody = JSON.stringify(json); + const parsedUrl = url.parse(event.ResponseURL); + const req = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'content-type': '', + 'content-length': Buffer.byteLength(responseBody, 'utf8'), + }, + }; + const retryOptions = { + attempts: 5, + sleep: 1000, + }; + await withRetries(retryOptions, exports.external.sendHttpRequest)(req, responseBody); +} +async function defaultSendHttpRequest(options, responseBody) { + return new Promise((resolve, reject) => { + try { + const request = https.request(options, _ => resolve()); + request.on('error', reject); + request.write(responseBody); + request.end(); + } + catch (e) { + reject(e); + } + }); +} +function defaultLog(fmt, ...params) { + // eslint-disable-next-line no-console + console.log(fmt, ...params); +} +function withRetries(options, fn) { + return async (...xs) => { + let attempts = options.attempts; + let ms = options.sleep; + while (true) { + try { + return await fn(...xs); + } + catch (e) { + if (attempts-- <= 0) { + throw e; + } + await sleep(Math.floor(Math.random() * ms)); + ms *= 2; + } + } + }; +} +exports.withRetries = withRetries; +async function sleep(ms) { + return new Promise((ok) => setTimeout(ok, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWpzLWVudHJ5cG9pbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJub2RlanMtZW50cnlwb2ludC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBRTNCLGlCQUFpQjtBQUNKLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLGVBQWUsRUFBRSxzQkFBc0I7SUFDdkMsR0FBRyxFQUFFLFVBQVU7SUFDZixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGdCQUFnQixFQUFFLFNBQVM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sZ0NBQWdDLEdBQUcsd0RBQXdELENBQUM7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyw4REFBOEQsQ0FBQztBQVczRixLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQWtELEVBQUUsT0FBMEI7SUFDMUcsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDeEQsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFM0QsdUVBQXVFO0lBQ3ZFLHVFQUF1RTtJQUN2RSxhQUFhO0lBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssZ0NBQWdDLEVBQUU7UUFDbkcsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN0RSxNQUFNLGNBQWMsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsT0FBTztLQUNSO0lBRUQsSUFBSTtRQUNGLHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsd0NBQXdDO1FBQ3hDLGlFQUFpRTtRQUNqRSxNQUFNLFdBQVcsR0FBWSxPQUFPLENBQUMsZ0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxNQUFN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LE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBSyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxFQUFFO1lBQ1gsSUFBSTtnQkFDRixPQUFPLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDeEI7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDbkIsTUFBTSxDQUFDLENBQUM7aUJBQ1Q7Z0JBQ0QsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNUO1NBQ0Y7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDO0FBaEJELGtDQWdCQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM3QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG4vLyBmb3IgdW5pdCB0ZXN0c1xuZXhwb3J0IGNvbnN0IGV4dGVybmFsID0ge1xuICBzZW5kSHR0cFJlcXVlc3Q6IGRlZmF1bHRTZW5kSHR0cFJlcXVlc3QsXG4gIGxvZzogZGVmYXVsdExvZyxcbiAgaW5jbHVkZVN0YWNrVHJhY2VzOiB0cnVlLFxuICB1c2VySGFuZGxlckluZGV4OiAnLi9pbmRleCcsXG59O1xuXG5jb25zdCBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6OkNSRUFURV9GQUlMRUQnO1xuY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IHR5cGUgUmVzcG9uc2UgPSBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgSGFuZGxlclJlc3BvbnNlO1xuZXhwb3J0IHR5cGUgSGFuZGxlciA9IChldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpID0+IFByb21pc2U8SGFuZGxlclJlc3BvbnNlIHwgdm9pZD47XG5leHBvcnQgdHlwZSBIYW5kbGVyUmVzcG9uc2UgPSB1bmRlZmluZWQgfCB7XG4gIERhdGE/OiBhbnk7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBOb0VjaG8/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIGNvbnRleHQ6IEFXU0xhbWJkYS5Db250ZXh0KSB7XG4gIGNvbnN0IHNhbml0aXplZEV2ZW50ID0geyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH07XG4gIGV4dGVybmFsLmxvZyhKU09OLnN0cmluZ2lmeShzYW5pdGl6ZWRFdmVudCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgLy8gaWdub3JlIERFTEVURSBldmVudCB3aGVuIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBJRCBpcyB0aGUgbWFya2VyIHRoYXRcbiAgLy8gaW5kaWNhdGVzIHRoYXQgdGhpcyBERUxFVEUgaXMgYSBzdWJzZXF1ZW50IERFTEVURSB0byBhIGZhaWxlZCBDUkVBVEVcbiAgLy8gb3BlcmF0aW9uLlxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9PT0gQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIpIHtcbiAgICBleHRlcm5hbC5sb2coJ2lnbm9yaW5nIERFTEVURSBldmVudCBjYXVzZWQgYnkgYSBmYWlsZWQgQ1JFQVRFIGV2ZW50Jyk7XG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBpbnZva2UgdGhlIHVzZXIgaGFuZGxlci4gdGhpcyBpcyBpbnRlbnRpb25hbGx5IGluc2lkZSB0aGUgdHJ5LWNhdGNoIHRvXG4gICAgLy8gZW5zdXJlIHRoYXQgaWYgdGhlcmUgaXMgYW4gZXJyb3IgaXQncyByZXBvcnRlZCBhcyBhIGZhaWx1cmUgdG9cbiAgICAvLyBjbG91ZGZvcm1hdGlvbiAob3RoZXJ3aXNlIGNmbiB3YWl0cykuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB1c2VySGFuZGxlcjogSGFuZGxlciA9IHJlcXVpcmUoZXh0ZXJuYWwudXNlckhhbmRsZXJJbmRleCkuaGFuZGxlcjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB1c2VySGFuZGxlcihzYW5pdGl6ZWRFdmVudCwgY29udGV4dCk7XG5cbiAgICAvLyB2YWxpZGF0ZSB1c2VyIHJlc3BvbnNlIGFuZCBjcmVhdGUgdGhlIGNvbWJpbmVkIGV2ZW50XG4gICAgY29uc3QgcmVzcG9uc2VFdmVudCA9IHJlbmRlclJlc3BvbnNlKGV2ZW50LCByZXN1bHQpO1xuXG4gICAgLy8gc3VibWl0IHRvIGNmbiBhcyBzdWNjZXNzXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCByZXNwb25zZUV2ZW50KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc3QgcmVzcDogUmVzcG9uc2UgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlYXNvbjogZXh0ZXJuYWwuaW5jbHVkZVN0YWNrVHJhY2VzID8gZS5zdGFjayA6IGUubWVzc2FnZSxcbiAgICB9O1xuXG4gICAgaWYgKCFyZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCkge1xuICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgLy8gaGF2ZSBhIHBoeXNpY2FsIHJlc291cmNlIGlkLiBpbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXF1ZW50IERFTEVURVxuICAgICAgLy8gb3BlcmF0aW9uIGRvZXMgbm90IGhhdmUgYW55IG1lYW5pbmcsIGFuZCB3aWxsIGxpa2VseSBmYWlsIGFzIHdlbGwuIHRvXG4gICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgIC8vIGlnbm9yZSB0aGUgc3Vic2VxdWVudCBERUxFVEUuXG4gICAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgICAgIGV4dGVybmFsLmxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICByZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpZiBQaHlzaWNhbFJlc291cmNlSWQgaXMgbm90IHNwZWNpZmllZCwgc29tZXRoaW5nIGlzXG4gICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgZXh0ZXJuYWwubG9nKGBFUlJPUjogTWFsZm9ybWVkIGV2ZW50LiBcIlBoeXNpY2FsUmVzb3VyY2VJZFwiIGlzIHJlcXVpcmVkOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyB0aGlzIGlzIGFuIGFjdHVhbCBlcnJvciwgZmFpbCB0aGUgYWN0aXZpdHkgYWx0b2dldGhlciBhbmQgZXhpc3QuXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ0ZBSUxFRCcsIHJlc3ApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlbmRlclJlc3BvbnNlKFxuICBjZm5SZXF1ZXN0OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgeyBQaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmcgfSxcbiAgaGFuZGxlclJlc3BvbnNlOiB2b2lkIHwgSGFuZGxlclJlc3BvbnNlID0geyB9KTogUmVzcG9uc2Uge1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gaGFuZGxlclJlc3BvbnNlLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlJlcXVlc3RJZDtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke2hhbmRsZXJSZXNwb25zZS5QaHlzaWNhbFJlc291cmNlSWR9XCIgZHVyaW5nIGRlbGV0aW9uYCk7XG4gIH1cblxuICAvLyBtZXJnZSByZXF1ZXN0IGV2ZW50IGFuZCByZXN1bHQgZXZlbnQgKHJlc3VsdCBwcmV2YWlscykuXG4gIHJldHVybiB7XG4gICAgLi4uY2ZuUmVxdWVzdCxcbiAgICAuLi5oYW5kbGVyUmVzcG9uc2UsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN1Ym1pdFJlc3BvbnNlKHN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsIGV2ZW50OiBSZXNwb25zZSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogZXZlbnQuUmVhc29uID8/IHN0YXR1cyxcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IE1JU1NJTkdfUEhZU0lDQUxfSURfTUFSS0VSLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBOb0VjaG86IGV2ZW50Lk5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGV4dGVybmFsLmxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGNvbnN0IHJlcSA9IHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcmV0cnlPcHRpb25zID0ge1xuICAgIGF0dGVtcHRzOiA1LFxuICAgIHNsZWVwOiAxMDAwLFxuICB9O1xuICBhd2FpdCB3aXRoUmV0cmllcyhyZXRyeU9wdGlvbnMsIGV4dGVybmFsLnNlbmRIdHRwUmVxdWVzdCkocmVxLCByZXNwb25zZUJvZHkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U2VuZEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBfID0+IHJlc29sdmUoKSk7XG4gICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICByZXF1ZXN0LndyaXRlKHJlc3BvbnNlQm9keSk7XG4gICAgICByZXF1ZXN0LmVuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0TG9nKGZtdDogc3RyaW5nLCAuLi5wYXJhbXM6IGFueVtdKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGZtdCwgLi4ucGFyYW1zKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICAvKiogSG93IG1hbnkgcmV0cmllcyAod2lsbCBhdCBsZWFzdCB0cnkgb25jZSkgKi9cbiAgcmVhZG9ubHkgYXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIFNsZWVwIGJhc2UsIGluIG1zICovXG4gIHJlYWRvbmx5IHNsZWVwOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUmV0cmllczxBIGV4dGVuZHMgQXJyYXk8YW55PiwgQj4ob3B0aW9uczogUmV0cnlPcHRpb25zLCBmbjogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+KTogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+IHtcbiAgcmV0dXJuIGFzeW5jICguLi54czogQSkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IG9wdGlvbnMuYXR0ZW1wdHM7XG4gICAgbGV0IG1zID0gb3B0aW9ucy5zbGVlcDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZuKC4uLnhzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGF0dGVtcHRzLS0gPD0gMCkge1xuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbXMpKTtcbiAgICAgICAgbXMgKj0gMjtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js new file mode 100644 index 0000000000000..bf260b9069cd1 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js @@ -0,0 +1,78 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handler = void 0; +// eslint-disable-next-line import/no-extraneous-dependencies +const aws_sdk_1 = require("aws-sdk"); +const AUTO_DELETE_OBJECTS_TAG = 'aws-cdk:auto-delete-objects'; +const s3 = new aws_sdk_1.S3(); +async function handler(event) { + switch (event.RequestType) { + case 'Create': + return; + case 'Update': + return onUpdate(event); + case 'Delete': + return onDelete(event.ResourceProperties?.BucketName); + } +} +exports.handler = handler; +async function onUpdate(event) { + const updateEvent = event; + const oldBucketName = updateEvent.OldResourceProperties?.BucketName; + const newBucketName = updateEvent.ResourceProperties?.BucketName; + const bucketNameHasChanged = newBucketName != null && oldBucketName != null && newBucketName !== oldBucketName; + /* If the name of the bucket has changed, CloudFormation will try to delete the bucket + and create a new one with the new name. So we have to delete the contents of the + bucket so that this operation does not fail. */ + if (bucketNameHasChanged) { + return onDelete(oldBucketName); + } +} +/** + * Recursively delete all items in the bucket + * + * @param bucketName the bucket name + */ +async function emptyBucket(bucketName) { + const listedObjects = await s3.listObjectVersions({ Bucket: bucketName }).promise(); + const contents = [...listedObjects.Versions ?? [], ...listedObjects.DeleteMarkers ?? []]; + if (contents.length === 0) { + return; + } + const records = contents.map((record) => ({ Key: record.Key, VersionId: record.VersionId })); + await s3.deleteObjects({ Bucket: bucketName, Delete: { Objects: records } }).promise(); + if (listedObjects?.IsTruncated) { + await emptyBucket(bucketName); + } +} +async function onDelete(bucketName) { + if (!bucketName) { + throw new Error('No BucketName was provided.'); + } + if (!await isBucketTaggedForDeletion(bucketName)) { + process.stdout.write(`Bucket does not have '${AUTO_DELETE_OBJECTS_TAG}' tag, skipping cleaning.\n`); + return; + } + try { + await emptyBucket(bucketName); + } + catch (e) { + if (e.code !== 'NoSuchBucket') { + throw e; + } + // Bucket doesn't exist. Ignoring + } +} +/** + * The bucket will only be tagged for deletion if it's being deleted in the same + * deployment as this Custom Resource. + * + * If the Custom Resource is every deleted before the bucket, it must be because + * `autoDeleteObjects` has been switched to false, in which case the tag would have + * been removed before we get to this Delete event. + */ +async function isBucketTaggedForDeletion(bucketName) { + const response = await s3.getBucketTagging({ Bucket: bucketName }).promise(); + return response.TagSet.some(tag => tag.Key === AUTO_DELETE_OBJECTS_TAG && tag.Value === 'true'); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBNkQ7QUFDN0QscUNBQTZCO0FBRTdCLE1BQU0sdUJBQXVCLEdBQUcsNkJBQTZCLENBQUM7QUFFOUQsTUFBTSxFQUFFLEdBQUcsSUFBSSxZQUFFLEVBQUUsQ0FBQztBQUViLEtBQUssVUFBVSxPQUFPLENBQUMsS0FBa0Q7SUFDOUUsUUFBUSxLQUFLLENBQUMsV0FBVyxFQUFFO1FBQ3pCLEtBQUssUUFBUTtZQUNYLE9BQU87UUFDVCxLQUFLLFFBQVE7WUFDWCxPQUFPLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6QixLQUFLLFFBQVE7WUFDWCxPQUFPLFFBQVEsQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsVUFBVSxDQUFDLENBQUM7S0FDekQ7QUFDSCxDQUFDO0FBVEQsMEJBU0M7QUFFRCxLQUFLLFVBQVUsUUFBUSxDQUFDLEtBQWtEO0lBQ3hFLE1BQU0sV0FBVyxHQUFHLEtBQTBELENBQUM7SUFDL0UsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFDLHFCQUFxQixFQUFFLFVBQVUsQ0FBQztJQUNwRSxNQUFNLGFBQWEsR0FBRyxXQUFXLENBQUMsa0JBQWtCLEVBQUUsVUFBVSxDQUFDO0lBQ2pFLE1BQU0sb0JBQW9CLEdBQUcsYUFBYSxJQUFJLElBQUksSUFBSSxhQUFhLElBQUksSUFBSSxJQUFJLGFBQWEsS0FBSyxhQUFhLENBQUM7SUFFL0c7O3NEQUVrRDtJQUNsRCxJQUFJLG9CQUFvQixFQUFFO1FBQ3hCLE9BQU8sUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0tBQ2hDO0FBQ0gsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxLQUFLLFVBQVUsV0FBVyxDQUFDLFVBQWtCO0lBQzNDLE1BQU0sYUFBYSxHQUFHLE1BQU0sRUFBRSxDQUFDLGtCQUFrQixDQUFDLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDcEYsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxRQUFRLElBQUksRUFBRSxFQUFFLEdBQUcsYUFBYSxDQUFDLGFBQWEsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN6RixJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQ3pCLE9BQU87S0FDUjtJQUVELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFXLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUcsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNsRyxNQUFNLEVBQUUsQ0FBQyxhQUFhLENBQUMsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFFdkYsSUFBSSxhQUFhLEVBQUUsV0FBVyxFQUFFO1FBQzlCLE1BQU0sV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0tBQy9CO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxRQUFRLENBQUMsVUFBbUI7SUFDekMsSUFBSSxDQUFDLFVBQVUsRUFBRTtRQUNmLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztLQUNoRDtJQUNELElBQUksQ0FBQyxNQUFNLHlCQUF5QixDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQ2hELE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5Qix1QkFBdUIsNkJBQTZCLENBQUMsQ0FBQztRQUNwRyxPQUFPO0tBQ1I7SUFDRCxJQUFJO1FBQ0YsTUFBTSxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7S0FDL0I7SUFBQyxPQUFPLENBQU0sRUFBRTtRQUNmLElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxjQUFjLEVBQUU7WUFDN0IsTUFBTSxDQUFDLENBQUM7U0FDVDtRQUNELGlDQUFpQztLQUNsQztBQUNILENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsS0FBSyxVQUFVLHlCQUF5QixDQUFDLFVBQWtCO0lBQ3pELE1BQU0sUUFBUSxHQUFHLE1BQU0sRUFBRSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDN0UsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssdUJBQXVCLElBQUksR0FBRyxDQUFDLEtBQUssS0FBSyxNQUFNLENBQUMsQ0FBQztBQUNsRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHsgUzMgfSBmcm9tICdhd3Mtc2RrJztcblxuY29uc3QgQVVUT19ERUxFVEVfT0JKRUNUU19UQUcgPSAnYXdzLWNkazphdXRvLWRlbGV0ZS1vYmplY3RzJztcblxuY29uc3QgczMgPSBuZXcgUzMoKTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQpIHtcbiAgc3dpdGNoIChldmVudC5SZXF1ZXN0VHlwZSkge1xuICAgIGNhc2UgJ0NyZWF0ZSc6XG4gICAgICByZXR1cm47XG4gICAgY2FzZSAnVXBkYXRlJzpcbiAgICAgIHJldHVybiBvblVwZGF0ZShldmVudCk7XG4gICAgY2FzZSAnRGVsZXRlJzpcbiAgICAgIHJldHVybiBvbkRlbGV0ZShldmVudC5SZXNvdXJjZVByb3BlcnRpZXM/LkJ1Y2tldE5hbWUpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG9uVXBkYXRlKGV2ZW50OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50KSB7XG4gIGNvbnN0IHVwZGF0ZUV2ZW50ID0gZXZlbnQgYXMgQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VVcGRhdGVFdmVudDtcbiAgY29uc3Qgb2xkQnVja2V0TmFtZSA9IHVwZGF0ZUV2ZW50Lk9sZFJlc291cmNlUHJvcGVydGllcz8uQnVja2V0TmFtZTtcbiAgY29uc3QgbmV3QnVja2V0TmFtZSA9IHVwZGF0ZUV2ZW50LlJlc291cmNlUHJvcGVydGllcz8uQnVja2V0TmFtZTtcbiAgY29uc3QgYnVja2V0TmFtZUhhc0NoYW5nZWQgPSBuZXdCdWNrZXROYW1lICE9IG51bGwgJiYgb2xkQnVja2V0TmFtZSAhPSBudWxsICYmIG5ld0J1Y2tldE5hbWUgIT09IG9sZEJ1Y2tldE5hbWU7XG5cbiAgLyogSWYgdGhlIG5hbWUgb2YgdGhlIGJ1Y2tldCBoYXMgY2hhbmdlZCwgQ2xvdWRGb3JtYXRpb24gd2lsbCB0cnkgdG8gZGVsZXRlIHRoZSBidWNrZXRcbiAgICAgYW5kIGNyZWF0ZSBhIG5ldyBvbmUgd2l0aCB0aGUgbmV3IG5hbWUuIFNvIHdlIGhhdmUgdG8gZGVsZXRlIHRoZSBjb250ZW50cyBvZiB0aGVcbiAgICAgYnVja2V0IHNvIHRoYXQgdGhpcyBvcGVyYXRpb24gZG9lcyBub3QgZmFpbC4gKi9cbiAgaWYgKGJ1Y2tldE5hbWVIYXNDaGFuZ2VkKSB7XG4gICAgcmV0dXJuIG9uRGVsZXRlKG9sZEJ1Y2tldE5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgZGVsZXRlIGFsbCBpdGVtcyBpbiB0aGUgYnVja2V0XG4gKlxuICogQHBhcmFtIGJ1Y2tldE5hbWUgdGhlIGJ1Y2tldCBuYW1lXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGVtcHR5QnVja2V0KGJ1Y2tldE5hbWU6IHN0cmluZykge1xuICBjb25zdCBsaXN0ZWRPYmplY3RzID0gYXdhaXQgczMubGlzdE9iamVjdFZlcnNpb25zKHsgQnVja2V0OiBidWNrZXROYW1lIH0pLnByb21pc2UoKTtcbiAgY29uc3QgY29udGVudHMgPSBbLi4ubGlzdGVkT2JqZWN0cy5WZXJzaW9ucyA/PyBbXSwgLi4ubGlzdGVkT2JqZWN0cy5EZWxldGVNYXJrZXJzID8/IFtdXTtcbiAgaWYgKGNvbnRlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHJlY29yZHMgPSBjb250ZW50cy5tYXAoKHJlY29yZDogYW55KSA9PiAoeyBLZXk6IHJlY29yZC5LZXksIFZlcnNpb25JZDogcmVjb3JkLlZlcnNpb25JZCB9KSk7XG4gIGF3YWl0IHMzLmRlbGV0ZU9iamVjdHMoeyBCdWNrZXQ6IGJ1Y2tldE5hbWUsIERlbGV0ZTogeyBPYmplY3RzOiByZWNvcmRzIH0gfSkucHJvbWlzZSgpO1xuXG4gIGlmIChsaXN0ZWRPYmplY3RzPy5Jc1RydW5jYXRlZCkge1xuICAgIGF3YWl0IGVtcHR5QnVja2V0KGJ1Y2tldE5hbWUpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG9uRGVsZXRlKGJ1Y2tldE5hbWU/OiBzdHJpbmcpIHtcbiAgaWYgKCFidWNrZXROYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBCdWNrZXROYW1lIHdhcyBwcm92aWRlZC4nKTtcbiAgfVxuICBpZiAoIWF3YWl0IGlzQnVja2V0VGFnZ2VkRm9yRGVsZXRpb24oYnVja2V0TmFtZSkpIHtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShgQnVja2V0IGRvZXMgbm90IGhhdmUgJyR7QVVUT19ERUxFVEVfT0JKRUNUU19UQUd9JyB0YWcsIHNraXBwaW5nIGNsZWFuaW5nLlxcbmApO1xuICAgIHJldHVybjtcbiAgfVxuICB0cnkge1xuICAgIGF3YWl0IGVtcHR5QnVja2V0KGJ1Y2tldE5hbWUpO1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBpZiAoZS5jb2RlICE9PSAnTm9TdWNoQnVja2V0Jykge1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gICAgLy8gQnVja2V0IGRvZXNuJ3QgZXhpc3QuIElnbm9yaW5nXG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgYnVja2V0IHdpbGwgb25seSBiZSB0YWdnZWQgZm9yIGRlbGV0aW9uIGlmIGl0J3MgYmVpbmcgZGVsZXRlZCBpbiB0aGUgc2FtZVxuICogZGVwbG95bWVudCBhcyB0aGlzIEN1c3RvbSBSZXNvdXJjZS5cbiAqXG4gKiBJZiB0aGUgQ3VzdG9tIFJlc291cmNlIGlzIGV2ZXJ5IGRlbGV0ZWQgYmVmb3JlIHRoZSBidWNrZXQsIGl0IG11c3QgYmUgYmVjYXVzZVxuICogYGF1dG9EZWxldGVPYmplY3RzYCBoYXMgYmVlbiBzd2l0Y2hlZCB0byBmYWxzZSwgaW4gd2hpY2ggY2FzZSB0aGUgdGFnIHdvdWxkIGhhdmVcbiAqIGJlZW4gcmVtb3ZlZCBiZWZvcmUgd2UgZ2V0IHRvIHRoaXMgRGVsZXRlIGV2ZW50LlxuICovXG5hc3luYyBmdW5jdGlvbiBpc0J1Y2tldFRhZ2dlZEZvckRlbGV0aW9uKGJ1Y2tldE5hbWU6IHN0cmluZykge1xuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHMzLmdldEJ1Y2tldFRhZ2dpbmcoeyBCdWNrZXQ6IGJ1Y2tldE5hbWUgfSkucHJvbWlzZSgpO1xuICByZXR1cm4gcmVzcG9uc2UuVGFnU2V0LnNvbWUodGFnID0+IHRhZy5LZXkgPT09IEFVVE9fREVMRVRFX09CSkVDVFNfVEFHICYmIHRhZy5WYWx1ZSA9PT0gJ3RydWUnKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/cdk.out b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json new file mode 100644 index 0000000000000..50b4d13c40618 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "31.0.0", + "testCases": { + "CloudFrontS3OriginOACTest/DefaultTest": { + "stacks": [ + "s3origin-oac-1", + "s3origin-oac-multistack" + ], + "assertionStack": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert", + "assertionStackName": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json new file mode 100644 index 0000000000000..77c4fb6775c7f --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json @@ -0,0 +1,237 @@ +{ + "version": "31.0.0", + "artifacts": { + "s3origin-oac-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "s3origin-oac-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "s3origin-oac-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "s3origin-oac-1.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}/975ebefe3e22c5aaee8a2186d6e669e28c4bfc37ea1a312bf0d1041fbcd1de51.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "s3origin-oac-1.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": [ + "s3origin-oac-1.assets" + ], + "metadata": { + "/s3origin-oac-1/Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Bucket83908E77" + } + ], + "/s3origin-oac-1/Bucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketPolicyE9A3008A" + } + ], + "/s3origin-oac-1/Bucket/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketAutoDeleteObjectsCustomResourceBAFD23C2" + } + ], + "/s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/s3origin-oac-1/OACNeverSign/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OACNeverSign93357AE1" + } + ], + "/s3origin-oac-1/DistDefault/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DistDefaultFA5D01D0" + } + ], + "/s3origin-oac-1/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + ], + "/s3origin-oac-1/DistNoPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DistNoPolicyC5896EBB" + } + ], + "/s3origin-oac-1/DistRWPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DistRWPolicy5EAF946C" + } + ], + "/s3origin-oac-1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + } + ], + "/s3origin-oac-1/Exports/Output{\"Ref\":\"Bucket83908E77\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefBucket83908E7781C90AC0" + } + ], + "/s3origin-oac-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/s3origin-oac-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "s3origin-oac-1" + }, + "s3origin-oac-multistack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "s3origin-oac-multistack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "s3origin-oac-multistack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "s3origin-oac-multistack.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}/a67e710f43b68ae6f010f859dec3c563f3637bb9ea3a9ffc40af3a93c5ab360e.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "s3origin-oac-multistack.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": [ + "s3origin-oac-1", + "s3origin-oac-multistack.assets" + ], + "metadata": { + "/s3origin-oac-multistack/DistCrossStack/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DistCrossStackDEBC5038" + } + ], + "/s3origin-oac-multistack/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + ], + "/s3origin-oac-multistack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/s3origin-oac-multistack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "s3origin-oac-multistack" + }, + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.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": [ + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.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": [ + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets" + ], + "metadata": { + "/CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json new file mode 100644 index 0000000000000..5ff5d77942e67 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json @@ -0,0 +1,32 @@ +{ + "version": "31.0.0", + "files": { + "40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9": { + "source": { + "path": "asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "975ebefe3e22c5aaee8a2186d6e669e28c4bfc37ea1a312bf0d1041fbcd1de51": { + "source": { + "path": "s3origin-oac-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "975ebefe3e22c5aaee8a2186d6e669e28c4bfc37ea1a312bf0d1041fbcd1de51.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-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.template.json new file mode 100644 index 0000000000000..afd00ebfe6841 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.template.json @@ -0,0 +1,617 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketPolicyE9A3008A": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "Bucket83908E77" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "s3:GetObject", + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistDefaultFA5D01D0" + } + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cloudfront.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistRWPolicy5EAF946C" + } + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cloudfront.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": "s3:GetObject", + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistRWPolicy5EAF946C" + } + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cloudfront.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "BucketAutoDeleteObjectsCustomResourceBAFD23C2": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "Bucket83908E77" + } + }, + "DependsOn": [ + "BucketPolicyE9A3008A" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] + } + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": "nodejs14.x", + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "Bucket83908E77" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ] + }, + "OACNeverSign93357AE1": { + "Type": "AWS::CloudFront::OriginAccessControl", + "Properties": { + "OriginAccessControlConfig": { + "Name": "s3originoac1OACNeverSign149329B5", + "OriginAccessControlOriginType": "s3", + "SigningBehavior": "never", + "SigningProtocol": "sigv4" + } + } + }, + "DistDefaultFA5D01D0": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "CacheBehaviors": [ + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "0/*", + "TargetOriginId": "s3originoac1DistDefaultOrigin29F927ED7", + "ViewerProtocolPolicy": "allow-all" + }, + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "1/*", + "TargetOriginId": "s3originoac1DistDefaultOrigin32A302443", + "ViewerProtocolPolicy": "allow-all" + }, + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "2/*", + "TargetOriginId": "s3originoac1DistDefaultOrigin428E3D9E3", + "ViewerProtocolPolicy": "allow-all" + } + ], + "DefaultCacheBehavior": { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "TargetOriginId": "s3originoac1DistDefaultOrigin1EAFF2C45", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistDefaultOrigin1EAFF2C45", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistDefaultOrigin29F927ED7", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistDefaultOrigin32A302443", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistDefaultOrigin428E3D9E3", + "OriginAccessControlId": { + "Ref": "OACNeverSign93357AE1" + }, + "S3OriginConfig": {} + } + ] + } + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28": { + "Type": "AWS::CloudFront::OriginAccessControl", + "Properties": { + "OriginAccessControlConfig": { + "Name": "s3originoac1OriginAccessContEFE0CA7DB170D0C7D8E8DC4943CF08146470", + "OriginAccessControlOriginType": "s3", + "SigningBehavior": "always", + "SigningProtocol": "sigv4" + } + } + }, + "DistNoPolicyC5896EBB": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "CacheBehaviors": [ + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "0/*", + "TargetOriginId": "s3originoac1DistNoPolicyOrigin21D41D317", + "ViewerProtocolPolicy": "allow-all" + }, + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "1/*", + "TargetOriginId": "s3originoac1DistNoPolicyOrigin37FFA8314", + "ViewerProtocolPolicy": "allow-all" + }, + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "2/*", + "TargetOriginId": "s3originoac1DistNoPolicyOrigin4E5B59189", + "ViewerProtocolPolicy": "allow-all" + } + ], + "DefaultCacheBehavior": { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "TargetOriginId": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistNoPolicyOrigin21D41D317", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::Join": [ + "", + [ + "s3origin-oac-test-bucket.s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "Id": "s3originoac1DistNoPolicyOrigin37FFA8314", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::Join": [ + "", + [ + { + "Ref": "Bucket83908E77" + }, + ".s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "Id": "s3originoac1DistNoPolicyOrigin4E5B59189", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + } + ] + } + } + }, + "DistRWPolicy5EAF946C": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "CacheBehaviors": [ + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "0/*", + "TargetOriginId": "s3originoac1DistRWPolicyOrigin27A3089D1", + "ViewerProtocolPolicy": "allow-all" + } + ], + "DefaultCacheBehavior": { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "TargetOriginId": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "s3originoac1DistRWPolicyOrigin27A3089D1", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + } + ] + } + } + } + }, + "Outputs": { + "ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631": { + "Value": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Export": { + "Name": "s3origin-oac-1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + } + }, + "ExportsOutputRefBucket83908E7781C90AC0": { + "Value": { + "Ref": "Bucket83908E77" + }, + "Export": { + "Name": "s3origin-oac-1:ExportsOutputRefBucket83908E7781C90AC0" + } + } + }, + "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-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json new file mode 100644 index 0000000000000..f9b1e6ceebe60 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "a67e710f43b68ae6f010f859dec3c563f3637bb9ea3a9ffc40af3a93c5ab360e": { + "source": { + "path": "s3origin-oac-multistack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a67e710f43b68ae6f010f859dec3c563f3637bb9ea3a9ffc40af3a93c5ab360e.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-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json new file mode 100644 index 0000000000000..09e27a21af9ad --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json @@ -0,0 +1,111 @@ +{ + "Resources": { + "DistCrossStackDEBC5038": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "CacheBehaviors": [ + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "0/*", + "TargetOriginId": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", + "ViewerProtocolPolicy": "allow-all" + } + ], + "DefaultCacheBehavior": { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "TargetOriginId": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "DomainName": { + "Fn::ImportValue": "s3origin-oac-1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + }, + "Id": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "s3origin-oac-1:ExportsOutputRefBucket83908E7781C90AC0" + }, + ".s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "Id": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + } + ] + } + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28": { + "Type": "AWS::CloudFront::OriginAccessControl", + "Properties": { + "OriginAccessControlConfig": { + "Name": "s3originoacmultistackOriginAEFE0CA7DB170D0C7D8E8DC4943CF8E9591F8", + "OriginAccessControlOriginType": "s3", + "SigningBehavior": "always", + "SigningProtocol": "sigv4" + } + } + } + }, + "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-origins/test/integ.s3-origin-oac.js.snapshot/tree.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/tree.json new file mode 100644 index 0000000000000..4cd04ac756bc6 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/tree.json @@ -0,0 +1,1035 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "s3origin-oac-1": { + "id": "s3origin-oac-1", + "path": "s3origin-oac-1", + "children": { + "Bucket": { + "id": "Bucket", + "path": "s3origin-oac-1/Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "s3origin-oac-1/Bucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "aws-cdk:auto-delete-objects", + "value": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "s3origin-oac-1/Bucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "s3origin-oac-1/Bucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "Bucket83908E77" + }, + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "s3:GetObject", + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistDefaultFA5D01D0" + } + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cloudfront.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistRWPolicy5EAF946C" + } + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cloudfront.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": "s3:GetObject", + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistRWPolicy5EAF946C" + } + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cloudfront.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + }, + "AutoDeleteObjectsCustomResource": { + "id": "AutoDeleteObjectsCustomResource", + "path": "s3origin-oac-1/Bucket/AutoDeleteObjectsCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "s3origin-oac-1/Bucket/AutoDeleteObjectsCustomResource/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "Custom::S3AutoDeleteObjectsCustomResourceProvider": { + "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", + "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Role": { + "id": "Role", + "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Handler": { + "id": "Handler", + "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "BucketHardcoded": { + "id": "BucketHardcoded", + "path": "s3origin-oac-1/BucketHardcoded", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + }, + "BucketImported": { + "id": "BucketImported", + "path": "s3origin-oac-1/BucketImported", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + }, + "OACNeverSign": { + "id": "OACNeverSign", + "path": "s3origin-oac-1/OACNeverSign", + "children": { + "Resource": { + "id": "Resource", + "path": "s3origin-oac-1/OACNeverSign/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", + "aws:cdk:cloudformation:props": { + "originAccessControlConfig": { + "name": "s3originoac1OACNeverSign149329B5", + "originAccessControlOriginType": "s3", + "signingBehavior": "never", + "signingProtocol": "sigv4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.OriginAccessControl", + "version": "0.0.0" + } + }, + "DistDefault": { + "id": "DistDefault", + "path": "s3origin-oac-1/DistDefault", + "children": { + "Origin1": { + "id": "Origin1", + "path": "s3origin-oac-1/DistDefault/Origin1", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "s3origin-oac-1/DistDefault/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "origins": [ + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistDefaultOrigin1EAFF2C45", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistDefaultOrigin29F927ED7", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistDefaultOrigin32A302443", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistDefaultOrigin428E3D9E3", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OACNeverSign93357AE1" + } + } + ], + "defaultCacheBehavior": { + "pathPattern": "*", + "targetOriginId": "s3originoac1DistDefaultOrigin1EAFF2C45", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + "cacheBehaviors": [ + { + "pathPattern": "0/*", + "targetOriginId": "s3originoac1DistDefaultOrigin29F927ED7", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + { + "pathPattern": "1/*", + "targetOriginId": "s3originoac1DistDefaultOrigin32A302443", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + { + "pathPattern": "2/*", + "targetOriginId": "s3originoac1DistDefaultOrigin428E3D9E3", + "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" + } + }, + "Origin2": { + "id": "Origin2", + "path": "s3origin-oac-1/DistDefault/Origin2", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Origin3": { + "id": "Origin3", + "path": "s3origin-oac-1/DistDefault/Origin3", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Origin4": { + "id": "Origin4", + "path": "s3origin-oac-1/DistDefault/Origin4", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.Distribution", + "version": "0.0.0" + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF": { + "id": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "path": "s3origin-oac-1/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "children": { + "Resource": { + "id": "Resource", + "path": "s3origin-oac-1/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", + "aws:cdk:cloudformation:props": { + "originAccessControlConfig": { + "name": "s3originoac1OriginAccessContEFE0CA7DB170D0C7D8E8DC4943CF08146470", + "originAccessControlOriginType": "s3", + "signingBehavior": "always", + "signingProtocol": "sigv4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.OriginAccessControl", + "version": "0.0.0" + } + }, + "DistNoPolicy": { + "id": "DistNoPolicy", + "path": "s3origin-oac-1/DistNoPolicy", + "children": { + "Origin1": { + "id": "Origin1", + "path": "s3origin-oac-1/DistNoPolicy/Origin1", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "s3origin-oac-1/DistNoPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "origins": [ + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistNoPolicyOrigin21D41D317", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::Join": [ + "", + [ + "s3origin-oac-test-bucket.s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "id": "s3originoac1DistNoPolicyOrigin37FFA8314", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::Join": [ + "", + [ + { + "Ref": "Bucket83908E77" + }, + ".s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "id": "s3originoac1DistNoPolicyOrigin4E5B59189", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + } + ], + "defaultCacheBehavior": { + "pathPattern": "*", + "targetOriginId": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + "cacheBehaviors": [ + { + "pathPattern": "0/*", + "targetOriginId": "s3originoac1DistNoPolicyOrigin21D41D317", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + { + "pathPattern": "1/*", + "targetOriginId": "s3originoac1DistNoPolicyOrigin37FFA8314", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + { + "pathPattern": "2/*", + "targetOriginId": "s3originoac1DistNoPolicyOrigin4E5B59189", + "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" + } + }, + "Origin2": { + "id": "Origin2", + "path": "s3origin-oac-1/DistNoPolicy/Origin2", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Origin3": { + "id": "Origin3", + "path": "s3origin-oac-1/DistNoPolicy/Origin3", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Origin4": { + "id": "Origin4", + "path": "s3origin-oac-1/DistNoPolicy/Origin4", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.Distribution", + "version": "0.0.0" + } + }, + "DistRWPolicy": { + "id": "DistRWPolicy", + "path": "s3origin-oac-1/DistRWPolicy", + "children": { + "Origin1": { + "id": "Origin1", + "path": "s3origin-oac-1/DistRWPolicy/Origin1", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "s3origin-oac-1/DistRWPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "origins": [ + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "id": "s3originoac1DistRWPolicyOrigin27A3089D1", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + } + ], + "defaultCacheBehavior": { + "pathPattern": "*", + "targetOriginId": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + "cacheBehaviors": [ + { + "pathPattern": "0/*", + "targetOriginId": "s3originoac1DistRWPolicyOrigin27A3089D1", + "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" + } + }, + "Origin2": { + "id": "Origin2", + "path": "s3origin-oac-1/DistRWPolicy/Origin2", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.Distribution", + "version": "0.0.0" + } + }, + "Exports": { + "id": "Exports", + "path": "s3origin-oac-1/Exports", + "children": { + "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}", + "path": "s3origin-oac-1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Output{\"Ref\":\"Bucket83908E77\"}": { + "id": "Output{\"Ref\":\"Bucket83908E77\"}", + "path": "s3origin-oac-1/Exports/Output{\"Ref\":\"Bucket83908E77\"}", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "s3origin-oac-1/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "s3origin-oac-1/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "s3origin-oac-multistack": { + "id": "s3origin-oac-multistack", + "path": "s3origin-oac-multistack", + "children": { + "DistCrossStack": { + "id": "DistCrossStack", + "path": "s3origin-oac-multistack/DistCrossStack", + "children": { + "Origin1": { + "id": "Origin1", + "path": "s3origin-oac-multistack/DistCrossStack/Origin1", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "s3origin-oac-multistack/DistCrossStack/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "origins": [ + { + "domainName": { + "Fn::ImportValue": "s3origin-oac-1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + }, + "id": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "s3origin-oac-1:ExportsOutputRefBucket83908E7781C90AC0" + }, + ".s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "id": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + } + ], + "defaultCacheBehavior": { + "pathPattern": "*", + "targetOriginId": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + "cacheBehaviors": [ + { + "pathPattern": "0/*", + "targetOriginId": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", + "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" + } + }, + "Origin2": { + "id": "Origin2", + "path": "s3origin-oac-multistack/DistCrossStack/Origin2", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.Distribution", + "version": "0.0.0" + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF": { + "id": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "path": "s3origin-oac-multistack/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "children": { + "Resource": { + "id": "Resource", + "path": "s3origin-oac-multistack/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", + "aws:cdk:cloudformation:props": { + "originAccessControlConfig": { + "name": "s3originoacmultistackOriginAEFE0CA7DB170D0C7D8E8DC4943CF8E9591F8", + "originAccessControlOriginType": "s3", + "signingBehavior": "always", + "signingProtocol": "sigv4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.OriginAccessControl", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "s3origin-oac-multistack/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "s3origin-oac-multistack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "CloudFrontS3OriginOACTest": { + "id": "CloudFrontS3OriginOACTest", + "path": "CloudFrontS3OriginOACTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "CloudFrontS3OriginOACTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "CloudFrontS3OriginOACTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts new file mode 100644 index 0000000000000..d7c060dbca6b1 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts @@ -0,0 +1,67 @@ +import * as cloudfront from '@aws-cdk/aws-cloudfront'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import * as origins from '../lib'; + +class S3OriginOAC extends origins.S3Origin { + constructor(bucket: s3.IBucket, props?: origins.S3OriginProps) { + if (props?.originAccessControl === undefined) { + props = { ...(props ?? {}), originAccessControl: true }; + } + super(bucket, props); + } +} + +function makeDistribution(stack: cdk.Stack, id: string, first: cloudfront.IOrigin, ...more: cloudfront.IOrigin[]) { + const dist = new cloudfront.Distribution(stack, id, { + defaultBehavior: { origin: first }, + }); + more.forEach((o, idx) => dist.addBehavior(`${idx}/*`, o)); +} + +const app = new cdk.App(); + +const stack1 = new cdk.Stack(app, 's3origin-oac-1'); +const bucket = new s3.Bucket(stack1, 'Bucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, +}); +const bucketByName = s3.Bucket.fromBucketName(stack1, 'BucketHardcoded', 's3origin-oac-test-bucket'); +const bucketImport = s3.Bucket.fromBucketName(stack1, 'BucketImported', bucket.bucketName); + +const oacCustom = new cloudfront.OriginAccessControl(stack1, 'OACNeverSign', { + originType: cloudfront.OriginAccessControlOriginType.S3, + signingBehavior: cloudfront.OriginAccessControlSigningBehavior.NEVER, +}); + +makeDistribution(stack1, 'DistDefault', + // this distribution will be granted access to the bucket via resource policy + new S3OriginOAC(bucket), + new S3OriginOAC(bucket, { autoResourcePolicy: true }), // should collapse with above + new S3OriginOAC(bucket, { autoResourcePolicy: false }), // no effect on policy + new S3OriginOAC(bucket, { originAccessControl: oacCustom }), +); +makeDistribution(stack1, 'DistNoPolicy', + // this distribution will not be granted access to any buckets via resource policy + new S3OriginOAC(bucket, { autoResourcePolicy: false }), + new S3OriginOAC(bucket, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.NONE }), + new S3OriginOAC(bucketByName, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.NONE }), + new S3OriginOAC(bucketImport, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.NONE }), +); +makeDistribution(stack1, 'DistRWPolicy', + // this distribution will be granted full read-write access to bucket via resource policy + new S3OriginOAC(bucket, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.READ_WRITE }), + new S3OriginOAC(bucket, { autoResourcePolicy: true }), // should collapse with above +); + +const stack2 = new cdk.Stack(app, 's3origin-oac-multistack'); +makeDistribution(stack2, 'DistCrossStack', + new S3OriginOAC(bucket, { autoResourcePolicy: false }), + new S3OriginOAC(bucketImport, { autoResourcePolicy: false }), +); + +new integ.IntegTest(app, 'CloudFrontS3OriginOACTest', { + testCases: [stack1, stack2], +}); +app.synth(); From 4517b6c90c1ec37fd769ed9a5ebe4e68ddf46957 Mon Sep 17 00:00:00 2001 From: Henry Goffin Date: Fri, 31 Mar 2023 13:35:35 +0000 Subject: [PATCH 4/7] add crazy resource policy modification lambda --- .../aws-cloudfront-origins/lib/s3-origin.ts | 40 +-- .../index.ts | 252 ++++++++++++++++++ .../lib/private/distribution-policy-setter.ts | 123 +++++++++ 3 files changed, 396 insertions(+), 19 deletions(-) create mode 100644 packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts diff --git a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts index 3f17c9fa21485..3b64332938829 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts @@ -4,6 +4,8 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { HttpOrigin } from './http-origin'; +// eslint-disable-next-line import/order +import { DistributionPolicySetter } from '@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter'; /** * Resource policy modification settings for S3 origins. @@ -129,30 +131,30 @@ class S3BucketOrigin extends cloudfront.OriginBase { private bindOAC(scope: Construct, options: cloudfront.OriginBindOptions): cloudfront.OriginBindConfig { if (this.autoResourcePolicy != S3OriginAutoResourcePolicy.NONE) { - if (cdk.Stack.of(this.bucket) != cdk.Stack.of(scope)) { - // The bucket policy must be mangaed by the same stack as the CloudFront distribution. - // If we do not check for this, it will create a circular cross-stack dependency. - throw new Error('Cannot edit cross-stack bucket policy due to circular dependency, set autoResourcePolicy to false'); - } const readonly = this.autoResourcePolicy == S3OriginAutoResourcePolicy.READ_ONLY; const dist = scope.node.scope as cloudfront.Distribution; const lazyDistArn = cdk.Lazy.string({ produce: () => dist.distributionArn }); - const added = this.bucket.addToResourcePolicy(new iam.PolicyStatement({ - principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')], - actions: readonly ? ['s3:GetObject'] : ['s3:GetObject', 's3:PutObject'], - resources: [this.bucket.arnForObjects('*')], - conditions: { StringEquals: { 'aws:SourceArn': lazyDistArn } }, - })); - if (!added.statementAdded) { - throw new Error('Cannot edit non-CDK-managed policy on imported buckets, set autoResourcePolicy to false'); + if (cdk.Stack.of(this.bucket) == cdk.Stack.of(scope)) { + // same stack - this "just works", the distribution does not depend on + // the resource policy (although it absolutely should, ideally) + const added = this.bucket.addToResourcePolicy(new iam.PolicyStatement({ + principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')], + actions: readonly ? ['s3:GetObject'] : ['s3:GetObject', 's3:PutObject'], + resources: [this.bucket.arnForObjects('*')], + conditions: { StringEquals: { 'aws:SourceArn': lazyDistArn } }, + })); + if (!added.statementAdded) { + throw new Error('Cannot apply autoResourcePolicy to imported buckets'); + } + } else { + if (!DistributionPolicySetter.configureBucket(dist, this.bucket, !readonly)) { + throw new Error('Cannot apply autoResourcePolicy to imported buckets'); + } } - // Buckets work because the bucket policies are only installed after the bucket - // is created, so the bucket policy can have a dependency on the distribution - // which depends on the bucket. But KMS keys need their policy at creation time, - // and there is no way to break the circular dependency with the distribution... - // unless we write a custom resource Lambda that modifies the key policy "later"? if (this.bucket.encryptionKey) { - throw new Error('Cannot edit KMS key policy due to circular dependency, set autoResourcePolicy to false'); + if (!DistributionPolicySetter.configureKey(dist, this.bucket.encryptionKey, !readonly)) { + throw new Error('Cannot apply autoResourcePolicy to imported KMS keys'); + } } } let oac = this.originAccessControl ?? true; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts new file mode 100644 index 0000000000000..546e335e5452a --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts @@ -0,0 +1,252 @@ +/* eslint-disable no-console */ +/* eslint-disable import/no-extraneous-dependencies */ +import { createHash, randomUUID } from 'crypto'; +import { S3, KMS } from 'aws-sdk'; + +// S3 handles cross-region redirection, can use a global API object +const s3 = new S3(); + +// KMS does not redirect across regions, requires a regional getter +const getKMSForRegion = (() => { + let kms: KMS | undefined; + return (region: string) => { + if (!kms || kms.config.region !== region) { + kms = new KMS({ region }); + } + return kms; + }; +})(); + +// We are not trying to do a complete parse of the Policy fields; +// we only verify enough of the type to safely make modifications. +interface BareMinimumStatement { + Sid?: string; + [key: string]: any; +} +interface BareMinimumPolicy { + Version: string; + Statement: BareMinimumStatement[]; + [key: string]: any; +} + +interface PermissionGrantStatement { + Sid: string; + Effect: 'Allow'; + Principal: { Service: 'cloudfront.amazonaws.com' }; + Action: string | string[]; + Resource: string | string[]; + Condition: { StringEquals: { 'aws:SourceArn': string } }; +} + +interface ArnParts { + partition?: string; + service?: string; + region?: string; + account?: string, + resource?: string; +} + +function isStringArray(x: any) : x is string[] { + return Array.isArray(x) && x.every(e => typeof e === 'string'); +} + +function generatePhysicalResourceId() { + return 'awscdk:distribution-policy-setter:' + randomUUID(); +} + +function generatePolicySid(physicalResourceId: string) { + const hash = createHash('sha256').update(physicalResourceId).digest('hex').slice(-32); + return 'DoNotEditCDKAutoPolicy' + hash; +} + +function parseArn(arn: string) : ArnParts | null { + const re = /^arn:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?[0-9]{12})?:(?.+)?$/; + return arn.match(re)?.groups ?? null; +} + +// parses JSON into a BareMinimumPolicy, or throws an error +function parsePolicyJSON(str: string | undefined, context: string) { + if (!str) { + throw new Error('unable to fetch policy document for ' + context); + } + let parsed: any; + try { + parsed = JSON.parse(str); + } catch { + throw new Error('unable to parse JSON policy document for ' + context); + } + // To maintain a good chance of forward-compatibility, this is a loose check: + // Version exists and is not too old for value references, and Statements is an + // array of objects each of which has an Effect string and maybe a Sid string. + if (typeof parsed !== 'object' || typeof parsed.Version !== 'string' || + parsed.Version.length != 10 || parsed.Version === '2008-10-17' || + !Array.isArray(parsed.Statement) ) { + throw new Error('invalid JSON policy document for ' + context); + } + for (const s of parsed.Statement) { + if (typeof s !== 'object' || !('Effect' in s) || typeof s.Effect !== 'string') { + throw new Error('invalid JSON policy statement for ' + context); + } + if ('Sid' in s && typeof s.Sid !== 'string') { + throw new Error('invalid JSON policy statement for ' + context); + } + } + return parsed as BareMinimumPolicy; +} + +// replace properties of one Statement with another; returns false if nothing changed +function replacePropertiesWith(dst: BareMinimumStatement, src: BareMinimumStatement) { + let didAnything = false; + for (const k in dst) { + if (!(k in src)) { + delete dst[k]; + didAnything = true; + } + } + for (const k in src) { + if (!(k in dst) || JSON.stringify(dst[k]) !== JSON.stringify(src[k])) { + dst[k] = src[k]; + didAnything = true; + } + } + return didAnything; +} + +// returns false if no changes were made to statements +function addOrReplacePolicyStatement( + s: BareMinimumStatement[], + desired: BareMinimumStatement & PermissionGrantStatement, + deleteOnly: boolean, + context: string, +) { + const found = s.map((_, i) => i).filter(i => s[i].Sid === desired.Sid); + if (found.length > 1) { + throw new Error('duplicate Sid in JSON policy document for ' + context); + } + if (deleteOnly) { + if (found.length == 1) { + s.splice(found[0], 1); + return true; + } else { + return false; + } + } else { + if (found.length == 1) { + return replacePropertiesWith(s[found[0]], desired); + } + s.push(desired); + return true; + } +} + +async function processArns( + uniqueSid: string, + distribution: string, + arnsRO: string[], + arnsRW: string[], + deleteOnly: boolean, +) { + for (const dryRun of [true, false]) { + const pairWith = (b:boolean) => ((e: string): [string, boolean] => [e, b]); + const mapped = arnsRO.map(pairWith(false)).concat(arnsRW.map(pairWith(true))); + for (const [arn, writeAccess] of mapped) { + console.log('processing ' + arn + (writeAccess ? ' (read-write)' : ' (read-only)') + (dryRun ? ' [DRY RUN]' : '')); + const arnParts = parseArn(arn); + if (!arnParts) { + throw new Error('unparseable arn ' + arn); + } + const arnResource = arnParts.resource ?? ''; + if (arnParts.service === 's3' && arnResource.length > 0 && !arnResource.includes('/')) { + const desired: PermissionGrantStatement = { + Sid: uniqueSid, + Effect: 'Allow', + Principal: { Service: 'cloudfront.amazonaws.com' }, + Action: writeAccess ? ['s3:GetObject', 's3:PutObject'] : 's3:GetObject', + Resource: arn + '/*', + Condition: { StringEquals: { 'aws:SourceArn': distribution } }, + }; + const get = await s3.getBucketPolicy({ Bucket: arnResource }).promise(); + const parsed = parsePolicyJSON(get.Policy, arn); + if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { + const put = await s3.putBucketPolicy({ Bucket: arnResource, Policy: JSON.stringify(parsed) }).promise(); + if (put.$response.httpResponse.statusCode != 200) { + throw new Error('unable to put new JSON policy document for ' + arn); + } + console.log('successfully modified ' + arn); + } + } else if (arnParts.service === 'kms' && arnParts.region && arnResource.startsWith('key/')) { + const desired: PermissionGrantStatement = { + Sid: uniqueSid, + Effect: 'Allow', + Principal: { Service: 'cloudfront.amazonaws.com' }, + Action: writeAccess ? ['kms:Decrypt', 'kms:Encrypt', 'kms:GetDataKey*'] : 'kms:Decrypt', + Resource: arn, + Condition: { StringEquals: { 'aws:SourceArn': distribution } }, + }; + const kms = getKMSForRegion(arnParts.region); + const get = await kms.getKeyPolicy({ KeyId: arn, PolicyName: 'default' }).promise(); + const parsed = parsePolicyJSON(get.Policy, arn); + if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { + const put = await kms.putKeyPolicy({ KeyId: arn, PolicyName: 'default', Policy: JSON.stringify(parsed) }).promise(); + if (put.$response.httpResponse.statusCode != 200) { + throw new Error('unable to put new JSON policy document for ' + arn); + } + console.log('successfully modified ' + arn); + } + } else { + throw new Error('unknown service for ' + arn); + } + } + } +} + +export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent) { + + let physicalId = String((event as any).PhysicalResourceId ?? generatePhysicalResourceId()); + + const dist = event.ResourceProperties.distribution; + const arnsRO = event.ResourceProperties.readOnlyArns; + const arnsRW = event.ResourceProperties.readWriteArns; + if (typeof dist !== 'string' || !dist.startsWith('arn:aws:cloudfront:')) { + throw new Error('invalid distribution property'); + } + if (!isStringArray(arnsRO) || !arnsRO.every(parseArn)) { + throw new Error('invalid readOnlyArns property'); + } + if (!isStringArray(arnsRW) || !arnsRW.every(parseArn)) { + throw new Error('invalid readWriteArns property'); + } + + const account = parseArn(event.ServiceToken)?.account; + if (!account || parseArn(dist)?.account !== account) { + throw new Error('invalid cross-account permission grant'); + } + + // If updating and the ARNs have changed, replace the physical ID + // to trigger a CloudFormation Delete request for the previous ID + // if (and only if) the update succeeds - a safe two-step commit! + if (event.RequestType === 'Update') { + const update = event as AWSLambda.CloudFormationCustomResourceUpdateEvent; + const oldarnsRO = update.OldResourceProperties.readOnlyArns ?? []; + const oldarnsRW = update.OldResourceProperties.readWriteArns ?? []; + if (JSON.stringify(oldarnsRO) !== JSON.stringify(arnsRO) || + JSON.stringify(oldarnsRW) !== JSON.stringify(arnsRW)) { + console.log('arns changed, generating new physical id'); + physicalId = generatePhysicalResourceId(); + } + } + + const dedupeSet = new Set(); + const hasNeverSeen = (e: string) => !dedupeSet.has(e) && !!dedupeSet.add(e); + // Process arnsRW first in case an ARN appears in both arnsRW and arnsRO + const dedupedRW = arnsRW.filter(hasNeverSeen); + const dedupedRO = arnsRO.filter(hasNeverSeen); + + const uniqueSid = generatePolicySid(physicalId); + const deleteOnly = event.RequestType === 'Delete'; + await processArns(uniqueSid, dist, dedupedRO, dedupedRW, deleteOnly); + + return { + PhysicalResourceId: physicalId, + }; +} diff --git a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts new file mode 100644 index 0000000000000..ec3846f0e4de8 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts @@ -0,0 +1,123 @@ +import * as path from 'path'; +import { ArnPrincipal, PolicyStatement, Effect } from '@aws-cdk/aws-iam'; +import { IKey } from '@aws-cdk/aws-kms'; +import { IBucket } from '@aws-cdk/aws-s3'; +import { CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, Lazy, Resource, Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { Distribution } from '..'; + +const POLICY_SETTER_RESOURCE_TYPE = 'Custom::CDKCloudFrontDistributionPolicySetter'; + +function getOrCreateProvider(scope: Construct) { + const uniqueId = 'PolicySetterProvider1eb96ce4e233406d91df225115785bdc'; + return CustomResourceProvider.getOrCreateProvider(scope, uniqueId, { + codeDirectory: path.join(__dirname, 'distribution-policy-setter-handler'), + runtime: CustomResourceProviderRuntime.NODEJS_16_X, + policyStatements: [ + { + Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:GetKeyPolicy', + 'kms:PutKeyPolicy', + 's3:GetBucketPolicy', + 's3:PutBucketPolicy', + ], + }, + ], + }); +} + +export class DistributionPolicySetter extends Construct { + + public static configureBucket(scope: Distribution, bucket: IBucket, writeAccess: boolean): boolean { + if (!Resource.isOwnedResource(bucket)) { + return false; + } + + const provider = getOrCreateProvider(bucket); + const added = bucket.addToResourcePolicy(new PolicyStatement({ + effect: Effect.ALLOW, + principals: [new ArnPrincipal(provider.roleArn)], + actions: ['s3:GetBucketPolicy', 's3:PutBucketPolicy'], + resources: [bucket.bucketArn], + })); + if (!added.statementAdded) { + return false; + } + + const setter = DistributionPolicySetter.getOrCreate(scope, bucket.stack); + if (writeAccess) { + setter.readWriteArns.push(bucket.bucketArn); + } else { + setter.readOnlyArns.push(bucket.bucketArn); + } + setter.node.addDependency(bucket); + if (bucket.policy) { + setter.node.addDependency(bucket.policy); + } + return true; + }; + + public static configureKey(scope: Distribution, key: IKey, writeAccess: boolean): boolean { + if (!Resource.isOwnedResource(key)) { + return false; + } + + const provider = getOrCreateProvider(key); + const added = key.addToResourcePolicy(new PolicyStatement({ + effect: Effect.ALLOW, + principals: [new ArnPrincipal(provider.roleArn)], + actions: ['kms:GetKeyPolicy', 'kms:PutKeyPolicy'], + resources: ['*'], + })); + if (!added.statementAdded) { + return false; + } + + const setter = DistributionPolicySetter.getOrCreate(scope, key.stack); + if (writeAccess) { + setter.readWriteArns.push(key.keyArn); + } else { + setter.readOnlyArns.push(key.keyArn); + } + setter.node.addDependency(key); + return true; + }; + + protected static getOrCreate(scope: Distribution, resourceStack: Stack) { + let counter = 1; + for (const child of scope.node.children) { + if (child instanceof DistributionPolicySetter) { + if (child.resourceStack == resourceStack) { + return child; + } + ++counter; + } + } + return new DistributionPolicySetter(scope, 'PolicySetter' + counter, resourceStack); + } + + private resourceStack : Stack; + private readOnlyArns : string[]; + private readWriteArns : string[]; + + private constructor(scope: Distribution, id: string, resourceStack: Stack) { + super(scope, id); + + this.resourceStack = resourceStack; + this.readOnlyArns = []; + this.readWriteArns = []; + + const customResource = new CustomResource(this, 'CustomResource', { + resourceType: POLICY_SETTER_RESOURCE_TYPE, + serviceToken: getOrCreateProvider(resourceStack).serviceToken, + properties: { + distribution: Lazy.string({ produce: () => scope.distributionArn }), + readOnlyArns: Lazy.list({ produce: () => this.readOnlyArns }), + readWriteArns: Lazy.list({ produce: () => this.readWriteArns }), + }, + }); + customResource.node.addDependency(this); + } +} From 553e4f0fd4d8b4d7a641df75ca3feafd0611c1b0 Mon Sep 17 00:00:00 2001 From: Henry Goffin Date: Sat, 1 Apr 2023 06:48:53 +0000 Subject: [PATCH 5/7] support cross-stack by splitting lambda from role --- .../index.ts | 45 +++-- .../lib/private/distribution-policy-setter.ts | 171 ++++++++++++++---- .../custom-resource-provider.ts | 20 +- 3 files changed, 179 insertions(+), 57 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts index 546e335e5452a..8b7dc4ac42198 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ /* eslint-disable import/no-extraneous-dependencies */ import { createHash, randomUUID } from 'crypto'; -import { S3, KMS } from 'aws-sdk'; +import { S3, KMS, HttpResponse } from 'aws-sdk'; // S3 handles cross-region redirection, can use a global API object const s3 = new S3(); @@ -29,6 +29,7 @@ interface BareMinimumPolicy { [key: string]: any; } +// We are a lot stricter about our own generated statements interface PermissionGrantStatement { Sid: string; Effect: 'Allow'; @@ -38,16 +39,17 @@ interface PermissionGrantStatement { Condition: { StringEquals: { 'aws:SourceArn': string } }; } -interface ArnParts { - partition?: string; - service?: string; - region?: string; - account?: string, - resource?: string; -} - -function isStringArray(x: any) : x is string[] { - return Array.isArray(x) && x.every(e => typeof e === 'string'); +function checkSuccessOrLogResponse(resp: HttpResponse | undefined | null) { + if (resp && resp.statusCode >= 200 && resp.statusCode <= 299) { + return true; + } + if (resp) { + console.log(`ERROR: ${resp.statusCode} ${resp.statusMessage}`); + console.log(resp.body.toString()); + } else { + console.log('ERROR: no response'); + } + return false; } function generatePhysicalResourceId() { @@ -59,8 +61,15 @@ function generatePolicySid(physicalResourceId: string) { return 'DoNotEditCDKAutoPolicy' + hash; } -function parseArn(arn: string) : ArnParts | null { - const re = /^arn:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?[0-9]{12})?:(?.+)?$/; +interface ParsedArn { + partition?: string; + service?: string; + region?: string; + account?: string, + resource?: string; +} +function parseArn(arn: string) : ParsedArn | null { + const re = /^arn:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?.+)?$/; return arn.match(re)?.groups ?? null; } @@ -112,7 +121,7 @@ function replacePropertiesWith(dst: BareMinimumStatement, src: BareMinimumStatem return didAnything; } -// returns false if no changes were made to statements +// modifies array in place; returns false if no changes were made to statements function addOrReplacePolicyStatement( s: BareMinimumStatement[], desired: BareMinimumStatement & PermissionGrantStatement, @@ -169,7 +178,7 @@ async function processArns( const parsed = parsePolicyJSON(get.Policy, arn); if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { const put = await s3.putBucketPolicy({ Bucket: arnResource, Policy: JSON.stringify(parsed) }).promise(); - if (put.$response.httpResponse.statusCode != 200) { + if (!checkSuccessOrLogResponse(put.$response.httpResponse)) { throw new Error('unable to put new JSON policy document for ' + arn); } console.log('successfully modified ' + arn); @@ -188,7 +197,7 @@ async function processArns( const parsed = parsePolicyJSON(get.Policy, arn); if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { const put = await kms.putKeyPolicy({ KeyId: arn, PolicyName: 'default', Policy: JSON.stringify(parsed) }).promise(); - if (put.$response.httpResponse.statusCode != 200) { + if (!checkSuccessOrLogResponse(put.$response.httpResponse)) { throw new Error('unable to put new JSON policy document for ' + arn); } console.log('successfully modified ' + arn); @@ -202,6 +211,10 @@ async function processArns( export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent) { + function isStringArray(x: any) : x is string[] { + return Array.isArray(x) && x.every(e => typeof e === 'string'); + } + let physicalId = String((event as any).PhysicalResourceId ?? generatePhysicalResourceId()); const dist = event.ResourceProperties.distribution; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts index ec3846f0e4de8..0937faffbef46 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts @@ -1,77 +1,160 @@ +import { createHash } from 'crypto'; import * as path from 'path'; import { ArnPrincipal, PolicyStatement, Effect } from '@aws-cdk/aws-iam'; -import { IKey } from '@aws-cdk/aws-kms'; -import { IBucket } from '@aws-cdk/aws-s3'; -import { CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, Lazy, Resource, Stack } from '@aws-cdk/core'; +import { CfnKey, IKey } from '@aws-cdk/aws-kms'; +import { CfnBucket, IBucket } from '@aws-cdk/aws-s3'; +import { CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, Lazy, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { Distribution } from '..'; - -const POLICY_SETTER_RESOURCE_TYPE = 'Custom::CDKCloudFrontDistributionPolicySetter'; - -function getOrCreateProvider(scope: Construct) { - const uniqueId = 'PolicySetterProvider1eb96ce4e233406d91df225115785bdc'; - return CustomResourceProvider.getOrCreateProvider(scope, uniqueId, { - codeDirectory: path.join(__dirname, 'distribution-policy-setter-handler'), - runtime: CustomResourceProviderRuntime.NODEJS_16_X, - policyStatements: [ - { - Effect: 'Allow', - Resource: '*', - Action: [ - 'kms:GetKeyPolicy', - 'kms:PutKeyPolicy', - 's3:GetBucketPolicy', - 's3:PutBucketPolicy', - ], - }, - ], +import { CfnDistribution, Distribution } from '..'; + +const CUSTOM_RESOURCE_TYPE = 'Custom::CDKCloudFrontDistributionPolicySetter'; + +function computeStackPairHash(distribution: Distribution, resourceStack: Stack) { + const uniqueStackPair = `${CUSTOM_RESOURCE_TYPE}|${distribution.stack.stackName}|${resourceStack.stackName}`; + return createHash('sha256').update(uniqueStackPair).digest('hex').slice(-32); +} + +function computePolicySetterTagName(distribution: Distribution, resourceStack: Stack) { + const uniqueHash = computeStackPairHash(distribution, resourceStack); + return `aws-cdk:allow-policy-setter:${uniqueHash}`; +} + +function computeSafetyCheckTagName(distribution: Distribution, resourceStack: Stack, writeAccess: boolean) { + // NOTE: This logic must be duplicated exactly in the lamda function implementation. + // We use a lazy evaluation because we want to defer getLogicalId, in case of renaming. + return Lazy.string({ + produce: () => { + let distLogicalId = distribution.stack.getLogicalId(distribution.node.defaultChild as CfnDistribution); + let verificationText = computeStackPairHash(distribution, resourceStack) + '|' + distLogicalId; + let verificationHash = createHash('sha256').update(verificationText).digest('hex').slice(-32); + return `aws-cdk:grant-distribution-${writeAccess ? 'rw' : 'ro'}:${verificationHash}`; + }, }); } +function getOrCreateProvider(distribution: Distribution, resourceStack: Stack) { + const uniqueHash = computeStackPairHash(distribution, resourceStack); + const providerId = 'PolicySetterProvider' + uniqueHash.toUpperCase(); + const roleParentId = 'PolicySetterRole' + uniqueHash.toUpperCase(); + + // Create a unique singleton construct in the resource stack to hold the Lambda + // execution role, which allows the resource stack to grant permissions to our + // custom resource function without creating a circular cross-stack dependency. + let roleParent = resourceStack.node.tryFindChild(roleParentId); + if (!(roleParent instanceof Construct)) { + roleParent = new Construct(resourceStack, roleParentId); + } + + const tagName = computePolicySetterTagName(distribution, resourceStack); + const conditionStringEquals: any = { }; + conditionStringEquals['aws:ResourceTag/' + tagName] = '1'; + + return CustomResourceProvider.getOrCreateProvider( + distribution.stack, + providerId, + { + codeDirectory: path.join(__dirname, 'distribution-policy-setter-handler'), + runtime: CustomResourceProviderRuntime.NODEJS_16_X, + roleParent: roleParent, + policyStatements: [ + { + Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:GetKeyPolicy', + 'kms:PutKeyPolicy', + 'kms:ListResourceTags', + 's3:GetBucketPolicy', + 's3:PutBucketPolicy', + 's3:GetBucketTagging', + ], + Condition: { StringEquals: conditionStringEquals }, + }, + ], + }, + ); +} + export class DistributionPolicySetter extends Construct { - public static configureBucket(scope: Distribution, bucket: IBucket, writeAccess: boolean): boolean { - if (!Resource.isOwnedResource(bucket)) { + public static configureBucket(scope: Distribution, bucket: IBucket, writeAccess: boolean, invalidatePath?: string): boolean { + let cfnbucket: CfnBucket; + if (bucket.node.defaultChild instanceof CfnBucket) { + cfnbucket = bucket.node.defaultChild as CfnBucket; + } else if (bucket.node.id.startsWith('@FromCfn') && bucket.node.scope instanceof CfnBucket) { + cfnbucket = bucket.node.scope as CfnBucket; + } else { return false; } - const provider = getOrCreateProvider(bucket); + const tagNameForDistribution = computeSafetyCheckTagName(scope, bucket.stack, writeAccess); + const tagNameForLambdaPermission = computePolicySetterTagName(scope, bucket.stack); + + if (cfnbucket.tags.tagValues()[tagNameForDistribution]) { + return true; // already tagged, permissions already granted to this distribution + } + + // If the necessary cross-resource policy has not already been added, add it. + const lazyArn = Lazy.string({ produce: () => getOrCreateProvider(scope, bucket.stack).roleArn }); const added = bucket.addToResourcePolicy(new PolicyStatement({ effect: Effect.ALLOW, - principals: [new ArnPrincipal(provider.roleArn)], + principals: [new ArnPrincipal(lazyArn)], actions: ['s3:GetBucketPolicy', 's3:PutBucketPolicy'], resources: [bucket.bucketArn], })); if (!added.statementAdded) { + // This CDK does not own this bucket policy and cannot modify it. return false; } + // Configure an invocation of the lambda function to add permissions for the distribution const setter = DistributionPolicySetter.getOrCreate(scope, bucket.stack); if (writeAccess) { setter.readWriteArns.push(bucket.bucketArn); } else { setter.readOnlyArns.push(bucket.bucketArn); } - setter.node.addDependency(bucket); - if (bucket.policy) { - setter.node.addDependency(bucket.policy); + if (invalidatePath && !setter.invalidatePaths.includes(invalidatePath)) { + setter.invalidatePaths.push(invalidatePath); } + setter.node.addDependency(cfnbucket); + setter.node.addDependency(bucket.policy!); + + // Make sure that the lambda role has permission to access this resource + cfnbucket.tags.setTag(tagNameForLambdaPermission, '1'); + + // Make sure the check-tag is set, or the lambda will refuse to modify the policy + cfnbucket.tags.setTag(tagNameForDistribution, '1'); + return true; }; - public static configureKey(scope: Distribution, key: IKey, writeAccess: boolean): boolean { - if (!Resource.isOwnedResource(key)) { + public static configureKey(scope: Distribution, key: IKey, writeAccess: boolean, invalidatePath?: string): boolean { + let cfnkey: CfnKey; + if (key.node.defaultChild instanceof CfnKey) { + cfnkey = key.node.defaultChild as CfnKey; + } else if (key.node.id.startsWith('@FromCfn') && key.node.scope instanceof CfnKey) { + cfnkey = key.node.scope as CfnKey; + } else { return false; } - const provider = getOrCreateProvider(key); + const tagNameForDistribution = computeSafetyCheckTagName(scope, key.stack, writeAccess); + const tagNameForLambdaPermission = computePolicySetterTagName(scope, key.stack); + + if (cfnkey.tags.tagValues()[tagNameForDistribution]) { + return true; // already tagged, permissions already granted to this distribution + } + + const lazyArn = Lazy.string({ produce: () => getOrCreateProvider(scope, key.stack).roleArn }); const added = key.addToResourcePolicy(new PolicyStatement({ effect: Effect.ALLOW, - principals: [new ArnPrincipal(provider.roleArn)], + principals: [new ArnPrincipal(lazyArn)], actions: ['kms:GetKeyPolicy', 'kms:PutKeyPolicy'], resources: ['*'], })); if (!added.statementAdded) { + // This CDK does not own this key policy and cannot modify it. return false; } @@ -81,7 +164,17 @@ export class DistributionPolicySetter extends Construct { } else { setter.readOnlyArns.push(key.keyArn); } - setter.node.addDependency(key); + if (invalidatePath && !setter.invalidatePaths.includes(invalidatePath)) { + setter.invalidatePaths.push(invalidatePath); + } + setter.node.addDependency(cfnkey); + + // Make sure that the lambda role has permission to access this resource + cfnkey.tags.setTag(tagNameForLambdaPermission, '1'); + + // Make sure the check-tag is set, or the lambda will refuse to modify the policy + cfnkey.tags.setTag(tagNameForDistribution, '1'); + return true; }; @@ -101,6 +194,7 @@ export class DistributionPolicySetter extends Construct { private resourceStack : Stack; private readOnlyArns : string[]; private readWriteArns : string[]; + private invalidatePaths: string[]; private constructor(scope: Distribution, id: string, resourceStack: Stack) { super(scope, id); @@ -108,10 +202,11 @@ export class DistributionPolicySetter extends Construct { this.resourceStack = resourceStack; this.readOnlyArns = []; this.readWriteArns = []; + this.invalidatePaths = []; const customResource = new CustomResource(this, 'CustomResource', { - resourceType: POLICY_SETTER_RESOURCE_TYPE, - serviceToken: getOrCreateProvider(resourceStack).serviceToken, + resourceType: CUSTOM_RESOURCE_TYPE, + serviceToken: getOrCreateProvider(scope, resourceStack).serviceToken, properties: { distribution: Lazy.string({ produce: () => scope.distributionArn }), readOnlyArns: Lazy.list({ produce: () => this.readOnlyArns }), diff --git a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts index 0eadacf4ebbb2..e19c61d5991b4 100644 --- a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts +++ b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts @@ -33,6 +33,15 @@ export interface CustomResourceProviderProps { */ readonly runtime: CustomResourceProviderRuntime; + /** + * An optional override for synthesizing the lambda execution role in a different stack. + * Moving role synthesis to an earlier stack can help break circular stack dependencies. + * + * @default - the lambda execution role is created in the same stack + * + */ + readonly roleParent?: Construct; + /** * A set of IAM policy statements to include in the inline policy of the * provider's lambda function. @@ -238,7 +247,12 @@ export class CustomResourceProvider extends Construct { } } - const config = getPrecreatedRoleConfig(this, `${this.node.path}/Role`); + let roleParent = props.roleParent ?? this; + if (roleParent.node.tryFindChild('Role')) { + throw new Error('roleParent already contains a construct with the id "Role"'); + } + + const config = getPrecreatedRoleConfig(roleParent, `${roleParent.node.path}/Role`); const assumeRolePolicyDoc = [{ Action: 'sts:AssumeRole', Effect: 'Allow', Principal: { Service: 'lambda.amazonaws.com' } }]; const managedPolicyArn = 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'; @@ -249,7 +263,7 @@ export class CustomResourceProvider extends Construct { // gives policyStatements a chance to resolve this.node.addValidation({ validate: () => { - PolicySynthesizer.getOrCreate(this).addRole(`${this.node.path}/Role`, { + PolicySynthesizer.getOrCreate(roleParent).addRole(`${roleParent.node.path}/Role`, { missing: !config.precreatedRoleName, roleName: config.precreatedRoleName ?? id+'Role', managedPolicies: [{ managedPolicyArn: managedPolicyArn }], @@ -267,7 +281,7 @@ export class CustomResourceProvider extends Construct { }); } if (!config.preventSynthesis) { - this._role = new CfnResource(this, 'Role', { + this._role = new CfnResource(roleParent, 'Role', { type: 'AWS::IAM::Role', properties: { AssumeRolePolicyDocument: { From 8fe71156e0770ded3e8375f74ed17b11e94be50f Mon Sep 17 00:00:00 2001 From: Henry Goffin Date: Sat, 1 Apr 2023 09:54:37 +0000 Subject: [PATCH 6/7] implement robust security tag checks --- .../index.ts | 92 ++++++++++++++++--- .../lib/private/distribution-policy-setter.ts | 42 +++++---- 2 files changed, 102 insertions(+), 32 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts index 8b7dc4ac42198..28751c0e7d84d 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter-handler/index.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ /* eslint-disable import/no-extraneous-dependencies */ import { createHash, randomUUID } from 'crypto'; -import { S3, KMS, HttpResponse } from 'aws-sdk'; +import { CloudFormation, HttpResponse, KMS, S3 } from 'aws-sdk'; // S3 handles cross-region redirection, can use a global API object const s3 = new S3(); @@ -53,12 +53,12 @@ function checkSuccessOrLogResponse(resp: HttpResponse | undefined | null) { } function generatePhysicalResourceId() { - return 'awscdk:distribution-policy-setter:' + randomUUID(); + return 'awscdk:distribution-policy-setter:' + randomUUID().replace('-', ''); } function generatePolicySid(physicalResourceId: string) { - const hash = createHash('sha256').update(physicalResourceId).digest('hex').slice(-32); - return 'DoNotEditCDKAutoPolicy' + hash; + const hash = physicalResourceId.split(':').at(-1); + return 'CDKDistributionPolicySetter' + hash?.toUpperCase(); } interface ParsedArn { @@ -148,24 +148,58 @@ function addOrReplacePolicyStatement( } } +async function lookupDistributionLogicalIdFromArn(distArn: string, stackId: string) { + const distId = distArn.split('distribution/').at(-1); + if (!distId || !distId.match(/^[0-9A-Z]+$/)) { + throw new Error('invalid distribution arn ' + distArn); + } + const cf = new CloudFormation({ apiVersion: '2010-05-15', region: parseArn(stackId)?.region }); + const describe = await cf.describeStackResources({ PhysicalResourceId: distId }).promise(); + if (!checkSuccessOrLogResponse(describe.$response.httpResponse)) { + throw new Error('unable to call describeStackResources on distribution id'); + } + const found = describe.StackResources?.find( + e => e.ResourceType === 'AWS::CloudFront::Distribution' && e.StackId === stackId, + ); + return found?.LogicalResourceId ?? null; +} + async function processArns( uniqueSid: string, distribution: string, arnsRO: string[], arnsRW: string[], deleteOnly: boolean, + tagNameRO: string, + tagNameRW: string, ) { for (const dryRun of [true, false]) { const pairWith = (b:boolean) => ((e: string): [string, boolean] => [e, b]); const mapped = arnsRO.map(pairWith(false)).concat(arnsRW.map(pairWith(true))); for (const [arn, writeAccess] of mapped) { console.log('processing ' + arn + (writeAccess ? ' (read-write)' : ' (read-only)') + (dryRun ? ' [DRY RUN]' : '')); + const arnParts = parseArn(arn); if (!arnParts) { throw new Error('unparseable arn ' + arn); } const arnResource = arnParts.resource ?? ''; + + const safetyCheckTag = writeAccess ? + ((k: string) => k === tagNameRW) : + ((k: string) => k === tagNameRW || k === tagNameRO); + if (arnParts.service === 's3' && arnResource.length > 0 && !arnResource.includes('/')) { + const s3tags = await s3.getBucketTagging({ Bucket: arnResource }).promise(); + if (!checkSuccessOrLogResponse(s3tags.$response.httpResponse)) { + throw new Error('unable to verify distribution safety-check tag for ' + arn); + } + const foundtag = s3tags?.TagSet?.map(e => e.Key)?.find(safetyCheckTag); + if (!foundtag) { + throw new Error('no matching distribution safety-check tag for ' + arn); + } + console.log('verified distribution safety-check tag ' + foundtag + ' for ' + arn); + const desired: PermissionGrantStatement = { Sid: uniqueSid, Effect: 'Allow', @@ -183,7 +217,25 @@ async function processArns( } console.log('successfully modified ' + arn); } + } else if (arnParts.service === 'kms' && arnParts.region && arnResource.startsWith('key/')) { + const kms = getKMSForRegion(arnParts.region); + + for (let marker = undefined;;) { + const kmstags = await kms.listResourceTags({ KeyId: arn, Marker: marker }).promise(); + if (!checkSuccessOrLogResponse(kmstags.$response.httpResponse)) { + throw new Error('unable to verify distribution safety-check tag for ' + arn); + } + const foundkey = kmstags.Tags?.map(e => e.TagKey)?.find(safetyCheckTag); + if (foundkey) { + console.log('verified distribution safety-check tag ' + foundkey + ' for ' + arn); + break; + } + if (!kmstags.Truncated || !kmstags.NextMarker) { + throw new Error('no matching distribution safety-check tag for ' + arn); + } + } + const desired: PermissionGrantStatement = { Sid: uniqueSid, Effect: 'Allow', @@ -192,7 +244,6 @@ async function processArns( Resource: arn, Condition: { StringEquals: { 'aws:SourceArn': distribution } }, }; - const kms = getKMSForRegion(arnParts.region); const get = await kms.getKeyPolicy({ KeyId: arn, PolicyName: 'default' }).promise(); const parsed = parsePolicyJSON(get.Policy, arn); if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { @@ -202,6 +253,7 @@ async function processArns( } console.log('successfully modified ' + arn); } + } else { throw new Error('unknown service for ' + arn); } @@ -215,8 +267,6 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent return Array.isArray(x) && x.every(e => typeof e === 'string'); } - let physicalId = String((event as any).PhysicalResourceId ?? generatePhysicalResourceId()); - const dist = event.ResourceProperties.distribution; const arnsRO = event.ResourceProperties.readOnlyArns; const arnsRW = event.ResourceProperties.readWriteArns; @@ -235,29 +285,43 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent throw new Error('invalid cross-account permission grant'); } - // If updating and the ARNs have changed, replace the physical ID + let physicalId = String((event as any).PhysicalResourceId ?? generatePhysicalResourceId()); + + // If updating and params have changed, replace the physical ID // to trigger a CloudFormation Delete request for the previous ID - // if (and only if) the update succeeds - a safe two-step commit! + // when (and if) the update succeeds - a safe two-phase commit. if (event.RequestType === 'Update') { const update = event as AWSLambda.CloudFormationCustomResourceUpdateEvent; + const olddist = update.OldResourceProperties.distribution ?? ''; const oldarnsRO = update.OldResourceProperties.readOnlyArns ?? []; const oldarnsRW = update.OldResourceProperties.readWriteArns ?? []; - if (JSON.stringify(oldarnsRO) !== JSON.stringify(arnsRO) || - JSON.stringify(oldarnsRW) !== JSON.stringify(arnsRW)) { - console.log('arns changed, generating new physical id'); + if (JSON.stringify([dist, arnsRO, arnsRW]) !== JSON.stringify([olddist, oldarnsRO, oldarnsRW])) { + console.log('parameters changed, generating new physical id'); physicalId = generatePhysicalResourceId(); } } + // Look up logical ID from distribution ID, verify against our stack ID + const distLogicalId = await lookupDistributionLogicalIdFromArn(dist, event.StackId); + if (!distLogicalId) { + throw new Error('unable to locate distribution in stack'); + } + + // NOTE: This logic must be duplicated exactly from computeSafetyCheckTagName + const safetyCheckText = process.env.CDK_STACK_NAME + '|' + distLogicalId; + const safetyCheckHash = createHash('sha256').update(safetyCheckText).digest('hex').slice(-32); + const tagNameRO = `aws-cdk:grant-distribution-ro:${safetyCheckHash}`; + const tagNameRW = `aws-cdk:grant-distribution-rw:${safetyCheckHash}`; + const dedupeSet = new Set(); const hasNeverSeen = (e: string) => !dedupeSet.has(e) && !!dedupeSet.add(e); // Process arnsRW first in case an ARN appears in both arnsRW and arnsRO const dedupedRW = arnsRW.filter(hasNeverSeen); const dedupedRO = arnsRO.filter(hasNeverSeen); - const uniqueSid = generatePolicySid(physicalId); + const policySid = generatePolicySid(physicalId); const deleteOnly = event.RequestType === 'Delete'; - await processArns(uniqueSid, dist, dedupedRO, dedupedRW, deleteOnly); + await processArns(policySid, dist, dedupedRO, dedupedRW, deleteOnly, tagNameRO, tagNameRW); return { PhysicalResourceId: physicalId, diff --git a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts index 0937faffbef46..d1aae85b1408c 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/private/distribution-policy-setter.ts @@ -19,14 +19,14 @@ function computePolicySetterTagName(distribution: Distribution, resourceStack: S return `aws-cdk:allow-policy-setter:${uniqueHash}`; } -function computeSafetyCheckTagName(distribution: Distribution, resourceStack: Stack, writeAccess: boolean) { - // NOTE: This logic must be duplicated exactly in the lamda function implementation. +function computeSafetyCheckTagName(distribution: Distribution, writeAccess: boolean) { + // NOTE: This logic must be duplicated exactly in the lambda function implementation. // We use a lazy evaluation because we want to defer getLogicalId, in case of renaming. return Lazy.string({ produce: () => { let distLogicalId = distribution.stack.getLogicalId(distribution.node.defaultChild as CfnDistribution); - let verificationText = computeStackPairHash(distribution, resourceStack) + '|' + distLogicalId; - let verificationHash = createHash('sha256').update(verificationText).digest('hex').slice(-32); + let hashtext = distribution.stack.stackName + '|' + distLogicalId; + let verificationHash = createHash('sha256').update(hashtext).digest('hex').slice(-32); return `aws-cdk:grant-distribution-${writeAccess ? 'rw' : 'ro'}:${verificationHash}`; }, }); @@ -46,8 +46,8 @@ function getOrCreateProvider(distribution: Distribution, resourceStack: Stack) { } const tagName = computePolicySetterTagName(distribution, resourceStack); - const conditionStringEquals: any = { }; - conditionStringEquals['aws:ResourceTag/' + tagName] = '1'; + const tagCheckStringEquals: any = { }; + tagCheckStringEquals['aws:ResourceTag/' + tagName] = '1'; return CustomResourceProvider.getOrCreateProvider( distribution.stack, @@ -55,11 +55,11 @@ function getOrCreateProvider(distribution: Distribution, resourceStack: Stack) { { codeDirectory: path.join(__dirname, 'distribution-policy-setter-handler'), runtime: CustomResourceProviderRuntime.NODEJS_16_X, + environment: { CDK_STACK_NAME: distribution.stack.stackName }, roleParent: roleParent, policyStatements: [ { Effect: 'Allow', - Resource: '*', Action: [ 'kms:GetKeyPolicy', 'kms:PutKeyPolicy', @@ -68,7 +68,13 @@ function getOrCreateProvider(distribution: Distribution, resourceStack: Stack) { 's3:PutBucketPolicy', 's3:GetBucketTagging', ], - Condition: { StringEquals: conditionStringEquals }, + Resource: '*', + Condition: { StringEquals: tagCheckStringEquals }, + }, + { + Effect: 'Allow', + Action: 'cloudformation:DescribeStackResources', + Resource: '*', }, ], }, @@ -87,11 +93,10 @@ export class DistributionPolicySetter extends Construct { return false; } - const tagNameForDistribution = computeSafetyCheckTagName(scope, bucket.stack, writeAccess); - const tagNameForLambdaPermission = computePolicySetterTagName(scope, bucket.stack); - + const tagNameForDistribution = computeSafetyCheckTagName(scope, writeAccess); if (cfnbucket.tags.tagValues()[tagNameForDistribution]) { - return true; // already tagged, permissions already granted to this distribution + // Already tagged, permissions already granted to this distribution + return true; } // If the necessary cross-resource policy has not already been added, add it. @@ -99,7 +104,7 @@ export class DistributionPolicySetter extends Construct { const added = bucket.addToResourcePolicy(new PolicyStatement({ effect: Effect.ALLOW, principals: [new ArnPrincipal(lazyArn)], - actions: ['s3:GetBucketPolicy', 's3:PutBucketPolicy'], + actions: ['s3:GetBucketPolicy', 's3:PutBucketPolicy', 's3:GetBucketTagging'], resources: [bucket.bucketArn], })); if (!added.statementAdded) { @@ -121,6 +126,7 @@ export class DistributionPolicySetter extends Construct { setter.node.addDependency(bucket.policy!); // Make sure that the lambda role has permission to access this resource + const tagNameForLambdaPermission = computePolicySetterTagName(scope, bucket.stack); cfnbucket.tags.setTag(tagNameForLambdaPermission, '1'); // Make sure the check-tag is set, or the lambda will refuse to modify the policy @@ -139,18 +145,17 @@ export class DistributionPolicySetter extends Construct { return false; } - const tagNameForDistribution = computeSafetyCheckTagName(scope, key.stack, writeAccess); - const tagNameForLambdaPermission = computePolicySetterTagName(scope, key.stack); - + const tagNameForDistribution = computeSafetyCheckTagName(scope, writeAccess); if (cfnkey.tags.tagValues()[tagNameForDistribution]) { - return true; // already tagged, permissions already granted to this distribution + // Already tagged, permissions already granted to this distribution + return true; } const lazyArn = Lazy.string({ produce: () => getOrCreateProvider(scope, key.stack).roleArn }); const added = key.addToResourcePolicy(new PolicyStatement({ effect: Effect.ALLOW, principals: [new ArnPrincipal(lazyArn)], - actions: ['kms:GetKeyPolicy', 'kms:PutKeyPolicy'], + actions: ['kms:GetKeyPolicy', 'kms:PutKeyPolicy', 'kms:ListResourceTags'], resources: ['*'], })); if (!added.statementAdded) { @@ -170,6 +175,7 @@ export class DistributionPolicySetter extends Construct { setter.node.addDependency(cfnkey); // Make sure that the lambda role has permission to access this resource + const tagNameForLambdaPermission = computePolicySetterTagName(scope, key.stack); cfnkey.tags.setTag(tagNameForLambdaPermission, '1'); // Make sure the check-tag is set, or the lambda will refuse to modify the policy From 014087ff83e103c9c0a6e9858652910f36c8c485 Mon Sep 17 00:00:00 2001 From: Henry Goffin Date: Sat, 1 Apr 2023 19:45:24 +0000 Subject: [PATCH 7/7] integration tests for everything --- .../cdk.out | 1 - ...-api-origin-custom-origin-path.assets.json | 19 - ...pi-origin-custom-origin-path.template.json | 234 ------ .../integ.json | 12 - .../manifest.json | 153 ---- .../tree.json | 407 ---------- ...faultTestDeployAssert62DBC588.assets.json} | 4 +- ...ultTestDeployAssert62DBC588.template.json} | 0 .../__entrypoint__.js | 0 .../index.js | 266 +++++++ .../cdk.out | 1 + .../integ.json | 13 + .../manifest.json | 255 ++++++ .../oacmulti1.assets.json} | 6 +- .../oacmulti1.template.json | 350 +++++++++ .../oacmulti2.assets.json} | 12 +- .../oacmulti2.template.json | 226 ++++++ .../tree.json | 735 +++++++++++++++++ .../test/integ.s3-origin-oac-multistack.ts | 50 ++ .../index.js | 78 -- .../__entrypoint__.js | 147 ++++ .../index.js | 266 +++++++ .../integ.json | 3 +- .../manifest.json | 118 +-- .../s3origin-oac-multistack.template.json | 111 --- .../s3origin-oac.assets.json | 32 + ...mplate.json => s3origin-oac.template.json} | 530 ++++++++----- .../integ.s3-origin-oac.js.snapshot/tree.json | 743 +++++++++--------- .../test/integ.s3-origin-oac.ts | 64 +- 29 files changed, 3129 insertions(+), 1707 deletions(-) delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/cdk.out delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.assets.json delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.template.json delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ.json delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/manifest.json delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/tree.json rename packages/@aws-cdk/aws-cloudfront-origins/test/{integ.rest-api-origin-custom-origin-path.ts.snapshot/restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.assets.json => integ.s3-origin-oac-multistack.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json} (83%) rename packages/@aws-cdk/aws-cloudfront-origins/test/{integ.rest-api-origin-custom-origin-path.ts.snapshot/restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.template.json => integ.s3-origin-oac-multistack.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.template.json} (100%) rename packages/@aws-cdk/aws-cloudfront-origins/test/{integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9 => integ.s3-origin-oac-multistack.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b}/__entrypoint__.js (100%) create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/manifest.json rename packages/@aws-cdk/aws-cloudfront-origins/test/{integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json => integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.assets.json} (65%) create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.template.json rename packages/@aws-cdk/aws-cloudfront-origins/test/{integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json => integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.assets.json} (63%) create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.ts delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/__entrypoint__.js create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js delete mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json create mode 100644 packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac.assets.json rename packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/{s3origin-oac-1.template.json => s3origin-oac.template.json} (62%) diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/cdk.out b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/cdk.out deleted file mode 100644 index ae4b03c54e770..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"30.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.assets.json deleted file mode 100644 index b98c6dc3fd1c3..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.assets.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "30.0.0", - "files": { - "caae80484d7f18b3e0e3e74d50e278f1f6a6f6ad5d264fa03a7fe46851fc2d8c": { - "source": { - "path": "integ-cloudfront-rest-api-origin-custom-origin-path.template.json", - "packaging": "file" - }, - "destinations": { - "current_account-current_region": { - "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "caae80484d7f18b3e0e3e74d50e278f1f6a6f6ad5d264fa03a7fe46851fc2d8c.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-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.template.json deleted file mode 100644 index ec611c3043c0b..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ-cloudfront-rest-api-origin-custom-origin-path.template.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "Resources": { - "RestApi0C43BF4B": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "EndpointConfiguration": { - "Types": [ - "REGIONAL" - ] - }, - "Name": "RestApi" - } - }, - "RestApiCloudWatchRoleE3ED6605": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "apigateway.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "ManagedPolicyArns": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" - ] - ] - } - ] - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "RestApiAccount7C83CF5A": { - "Type": "AWS::ApiGateway::Account", - "Properties": { - "CloudWatchRoleArn": { - "Fn::GetAtt": [ - "RestApiCloudWatchRoleE3ED6605", - "Arn" - ] - } - }, - "DependsOn": [ - "RestApi0C43BF4B" - ], - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "RestApiDeployment180EC50368af6d4b358eff290c08cb2de07c4042": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "RestApi0C43BF4B" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "RestApiGET0F59260B" - ] - }, - "RestApiDeploymentStageprod3855DE66": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "RestApi0C43BF4B" - }, - "DeploymentId": { - "Ref": "RestApiDeployment180EC50368af6d4b358eff290c08cb2de07c4042" - }, - "StageName": "prod" - }, - "DependsOn": [ - "RestApiAccount7C83CF5A" - ] - }, - "RestApiGET0F59260B": { - "Type": "AWS::ApiGateway::Method", - "Properties": { - "HttpMethod": "GET", - "ResourceId": { - "Fn::GetAtt": [ - "RestApi0C43BF4B", - "RootResourceId" - ] - }, - "RestApiId": { - "Ref": "RestApi0C43BF4B" - }, - "AuthorizationType": "NONE", - "Integration": { - "Type": "MOCK" - } - } - }, - "Distribution830FAC52": { - "Type": "AWS::CloudFront::Distribution", - "Properties": { - "DistributionConfig": { - "DefaultCacheBehavior": { - "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", - "Compress": true, - "TargetOriginId": "integcloudfrontrestapiorigincustomoriginpathDistributionOrigin1635825EA", - "ViewerProtocolPolicy": "allow-all" - }, - "Enabled": true, - "HttpVersion": "http2", - "IPV6Enabled": true, - "Origins": [ - { - "CustomOriginConfig": { - "OriginProtocolPolicy": "https-only", - "OriginSSLProtocols": [ - "TLSv1.2" - ] - }, - "DomainName": { - "Fn::Select": [ - 2, - { - "Fn::Split": [ - "/", - { - "Fn::Join": [ - "", - [ - "https://", - { - "Ref": "RestApi0C43BF4B" - }, - ".execute-api.", - { - "Ref": "AWS::Region" - }, - ".", - { - "Ref": "AWS::URLSuffix" - }, - "/", - { - "Ref": "RestApiDeploymentStageprod3855DE66" - }, - "/" - ] - ] - } - ] - } - ] - }, - "Id": "integcloudfrontrestapiorigincustomoriginpathDistributionOrigin1635825EA", - "OriginPath": "" - } - ] - } - } - } - }, - "Outputs": { - "RestApiEndpoint0551178A": { - "Value": { - "Fn::Join": [ - "", - [ - "https://", - { - "Ref": "RestApi0C43BF4B" - }, - ".execute-api.", - { - "Ref": "AWS::Region" - }, - ".", - { - "Ref": "AWS::URLSuffix" - }, - "/", - { - "Ref": "RestApiDeploymentStageprod3855DE66" - }, - "/" - ] - ] - } - } - }, - "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-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ.json deleted file mode 100644 index 36c91bc53e6e5..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/integ.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": "30.0.0", - "testCases": { - "rest-api-origin-custom-origin-path/DefaultTest": { - "stacks": [ - "integ-cloudfront-rest-api-origin-custom-origin-path" - ], - "assertionStack": "rest-api-origin-custom-origin-path/DefaultTest/DeployAssert", - "assertionStackName": "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/manifest.json deleted file mode 100644 index a88d1ede6370d..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/manifest.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "version": "30.0.0", - "artifacts": { - "integ-cloudfront-rest-api-origin-custom-origin-path.assets": { - "type": "cdk:asset-manifest", - "properties": { - "file": "integ-cloudfront-rest-api-origin-custom-origin-path.assets.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" - } - }, - "integ-cloudfront-rest-api-origin-custom-origin-path": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "integ-cloudfront-rest-api-origin-custom-origin-path.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}/caae80484d7f18b3e0e3e74d50e278f1f6a6f6ad5d264fa03a7fe46851fc2d8c.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", - "additionalDependencies": [ - "integ-cloudfront-rest-api-origin-custom-origin-path.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-cloudfront-rest-api-origin-custom-origin-path.assets" - ], - "metadata": { - "/integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "RestApi0C43BF4B" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/CloudWatchRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "RestApiCloudWatchRoleE3ED6605" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Account": [ - { - "type": "aws:cdk:logicalId", - "data": "RestApiAccount7C83CF5A" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Deployment/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "RestApiDeployment180EC50368af6d4b358eff290c08cb2de07c4042" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/DeploymentStage.prod/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "RestApiDeploymentStageprod3855DE66" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Endpoint": [ - { - "type": "aws:cdk:logicalId", - "data": "RestApiEndpoint0551178A" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Default/GET/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "RestApiGET0F59260B" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/Distribution/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "Distribution830FAC52" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/BootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "BootstrapVersion" - } - ], - "/integ-cloudfront-rest-api-origin-custom-origin-path/CheckBootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "CheckBootstrapVersion" - } - ] - }, - "displayName": "integ-cloudfront-rest-api-origin-custom-origin-path" - }, - "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.assets": { - "type": "cdk:asset-manifest", - "properties": { - "file": "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.assets.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" - } - }, - "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.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": [ - "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.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": [ - "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.assets" - ], - "metadata": { - "/rest-api-origin-custom-origin-path/DefaultTest/DeployAssert/BootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "BootstrapVersion" - } - ], - "/rest-api-origin-custom-origin-path/DefaultTest/DeployAssert/CheckBootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "CheckBootstrapVersion" - } - ] - }, - "displayName": "rest-api-origin-custom-origin-path/DefaultTest/DeployAssert" - }, - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/tree.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/tree.json deleted file mode 100644 index a5eeb05846cb0..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/tree.json +++ /dev/null @@ -1,407 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "integ-cloudfront-rest-api-origin-custom-origin-path": { - "id": "integ-cloudfront-rest-api-origin-custom-origin-path", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path", - "children": { - "RestApi": { - "id": "RestApi", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi", - "children": { - "Resource": { - "id": "Resource", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::ApiGateway::RestApi", - "aws:cdk:cloudformation:props": { - "endpointConfiguration": { - "types": [ - "REGIONAL" - ] - }, - "name": "RestApi" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.CfnRestApi", - "version": "0.0.0" - } - }, - "CloudWatchRole": { - "id": "CloudWatchRole", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/CloudWatchRole", - "children": { - "ImportCloudWatchRole": { - "id": "ImportCloudWatchRole", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/CloudWatchRole/ImportCloudWatchRole", - "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/CloudWatchRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "assumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "apigateway.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "managedPolicyArns": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Account": { - "id": "Account", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Account", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::ApiGateway::Account", - "aws:cdk:cloudformation:props": { - "cloudWatchRoleArn": { - "Fn::GetAtt": [ - "RestApiCloudWatchRoleE3ED6605", - "Arn" - ] - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.CfnAccount", - "version": "0.0.0" - } - }, - "Deployment": { - "id": "Deployment", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Deployment", - "children": { - "Resource": { - "id": "Resource", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Deployment/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::ApiGateway::Deployment", - "aws:cdk:cloudformation:props": { - "restApiId": { - "Ref": "RestApi0C43BF4B" - }, - "description": "Automatically created by the RestApi construct" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.CfnDeployment", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.Deployment", - "version": "0.0.0" - } - }, - "DeploymentStage.prod": { - "id": "DeploymentStage.prod", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/DeploymentStage.prod", - "children": { - "Resource": { - "id": "Resource", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/DeploymentStage.prod/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::ApiGateway::Stage", - "aws:cdk:cloudformation:props": { - "restApiId": { - "Ref": "RestApi0C43BF4B" - }, - "deploymentId": { - "Ref": "RestApiDeployment180EC50368af6d4b358eff290c08cb2de07c4042" - }, - "stageName": "prod" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.CfnStage", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.Stage", - "version": "0.0.0" - } - }, - "Endpoint": { - "id": "Endpoint", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Endpoint", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnOutput", - "version": "0.0.0" - } - }, - "Default": { - "id": "Default", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Default", - "children": { - "GET": { - "id": "GET", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Default/GET", - "children": { - "Resource": { - "id": "Resource", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/RestApi/Default/GET/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", - "aws:cdk:cloudformation:props": { - "httpMethod": "GET", - "resourceId": { - "Fn::GetAtt": [ - "RestApi0C43BF4B", - "RootResourceId" - ] - }, - "restApiId": { - "Ref": "RestApi0C43BF4B" - }, - "authorizationType": "NONE", - "integration": { - "type": "MOCK" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.CfnMethod", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.Method", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.ResourceBase", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-apigateway.RestApi", - "version": "0.0.0" - } - }, - "Distribution": { - "id": "Distribution", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/Distribution", - "children": { - "Origin1": { - "id": "Origin1", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/Distribution/Origin1", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.237" - } - }, - "Resource": { - "id": "Resource", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/Distribution/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", - "aws:cdk:cloudformation:props": { - "distributionConfig": { - "enabled": true, - "origins": [ - { - "domainName": { - "Fn::Select": [ - 2, - { - "Fn::Split": [ - "/", - { - "Fn::Join": [ - "", - [ - "https://", - { - "Ref": "RestApi0C43BF4B" - }, - ".execute-api.", - { - "Ref": "AWS::Region" - }, - ".", - { - "Ref": "AWS::URLSuffix" - }, - "/", - { - "Ref": "RestApiDeploymentStageprod3855DE66" - }, - "/" - ] - ] - } - ] - } - ] - }, - "id": "integcloudfrontrestapiorigincustomoriginpathDistributionOrigin1635825EA", - "originPath": "", - "customOriginConfig": { - "originSslProtocols": [ - "TLSv1.2" - ], - "originProtocolPolicy": "https-only" - } - } - ], - "defaultCacheBehavior": { - "pathPattern": "*", - "targetOriginId": "integcloudfrontrestapiorigincustomoriginpathDistributionOrigin1635825EA", - "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" - } - }, - "BootstrapVersion": { - "id": "BootstrapVersion", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/BootstrapVersion", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", - "version": "0.0.0" - } - }, - "CheckBootstrapVersion": { - "id": "CheckBootstrapVersion", - "path": "integ-cloudfront-rest-api-origin-custom-origin-path/CheckBootstrapVersion", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnRule", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" - } - }, - "rest-api-origin-custom-origin-path": { - "id": "rest-api-origin-custom-origin-path", - "path": "rest-api-origin-custom-origin-path", - "children": { - "DefaultTest": { - "id": "DefaultTest", - "path": "rest-api-origin-custom-origin-path/DefaultTest", - "children": { - "Default": { - "id": "Default", - "path": "rest-api-origin-custom-origin-path/DefaultTest/Default", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.237" - } - }, - "DeployAssert": { - "id": "DeployAssert", - "path": "rest-api-origin-custom-origin-path/DefaultTest/DeployAssert", - "children": { - "BootstrapVersion": { - "id": "BootstrapVersion", - "path": "rest-api-origin-custom-origin-path/DefaultTest/DeployAssert/BootstrapVersion", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", - "version": "0.0.0" - } - }, - "CheckBootstrapVersion": { - "id": "CheckBootstrapVersion", - "path": "rest-api-origin-custom-origin-path/DefaultTest/DeployAssert/CheckBootstrapVersion", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnRule", - "version": "0.0.0" - } - } - }, - "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" - } - }, - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.237" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json similarity index 83% rename from packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.assets.json rename to packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json index d9384c5bf3156..0e06662be879c 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.assets.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json @@ -1,9 +1,9 @@ { - "version": "30.0.0", + "version": "31.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { - "path": "restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.template.json", + "path": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.template.json", "packaging": "file" }, "destinations": { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.template.json similarity index 100% rename from packages/@aws-cdk/aws-cloudfront-origins/test/integ.rest-api-origin-custom-origin-path.ts.snapshot/restapiorigincustomoriginpathDefaultTestDeployAssertCD227A2A.template.json rename to packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.template.json diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/__entrypoint__.js b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/__entrypoint__.js similarity index 100% rename from packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/__entrypoint__.js rename to packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/__entrypoint__.js diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js new file mode 100644 index 0000000000000..355c354b96ef3 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js @@ -0,0 +1,266 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handler = void 0; +/* eslint-disable no-console */ +/* eslint-disable import/no-extraneous-dependencies */ +const crypto_1 = require("crypto"); +const aws_sdk_1 = require("aws-sdk"); +// S3 handles cross-region redirection, can use a global API object +const s3 = new aws_sdk_1.S3(); +// KMS does not redirect across regions, requires a regional getter +const getKMSForRegion = (() => { + let kms; + return (region) => { + if (!kms || kms.config.region !== region) { + kms = new aws_sdk_1.KMS({ region }); + } + return kms; + }; +})(); +function checkSuccessOrLogResponse(resp) { + if (resp && resp.statusCode >= 200 && resp.statusCode <= 299) { + return true; + } + if (resp) { + console.log(`ERROR: ${resp.statusCode} ${resp.statusMessage}`); + console.log(resp.body.toString()); + } + else { + console.log('ERROR: no response'); + } + return false; +} +function generatePhysicalResourceId() { + return 'awscdk:distribution-policy-setter:' + (0, crypto_1.randomUUID)().replace('-', ''); +} +function generatePolicySid(physicalResourceId) { + const hash = physicalResourceId.split(':').at(-1); + return 'CDKDistributionPolicySetter' + hash?.toUpperCase(); +} +function parseArn(arn) { + const re = /^arn:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?.+)?$/; + return arn.match(re)?.groups ?? null; +} +// parses JSON into a BareMinimumPolicy, or throws an error +function parsePolicyJSON(str, context) { + if (!str) { + throw new Error('unable to fetch policy document for ' + context); + } + let parsed; + try { + parsed = JSON.parse(str); + } + catch { + throw new Error('unable to parse JSON policy document for ' + context); + } + // To maintain a good chance of forward-compatibility, this is a loose check: + // Version exists and is not too old for value references, and Statements is an + // array of objects each of which has an Effect string and maybe a Sid string. + if (typeof parsed !== 'object' || typeof parsed.Version !== 'string' || + parsed.Version.length != 10 || parsed.Version === '2008-10-17' || + !Array.isArray(parsed.Statement)) { + throw new Error('invalid JSON policy document for ' + context); + } + for (const s of parsed.Statement) { + if (typeof s !== 'object' || !('Effect' in s) || typeof s.Effect !== 'string') { + throw new Error('invalid JSON policy statement for ' + context); + } + if ('Sid' in s && typeof s.Sid !== 'string') { + throw new Error('invalid JSON policy statement for ' + context); + } + } + return parsed; +} +// replace properties of one Statement with another; returns false if nothing changed +function replacePropertiesWith(dst, src) { + let didAnything = false; + for (const k in dst) { + if (!(k in src)) { + delete dst[k]; + didAnything = true; + } + } + for (const k in src) { + if (!(k in dst) || JSON.stringify(dst[k]) !== JSON.stringify(src[k])) { + dst[k] = src[k]; + didAnything = true; + } + } + return didAnything; +} +// modifies array in place; returns false if no changes were made to statements +function addOrReplacePolicyStatement(s, desired, deleteOnly, context) { + const found = s.map((_, i) => i).filter(i => s[i].Sid === desired.Sid); + if (found.length > 1) { + throw new Error('duplicate Sid in JSON policy document for ' + context); + } + if (deleteOnly) { + if (found.length == 1) { + s.splice(found[0], 1); + return true; + } + else { + return false; + } + } + else { + if (found.length == 1) { + return replacePropertiesWith(s[found[0]], desired); + } + s.push(desired); + return true; + } +} +async function lookupDistributionLogicalIdFromArn(distArn, stackId) { + const distId = distArn.split('distribution/').at(-1); + if (!distId || !distId.match(/^[0-9A-Z]+$/)) { + throw new Error('invalid distribution arn ' + distArn); + } + const cf = new aws_sdk_1.CloudFormation({ apiVersion: '2010-05-15', region: parseArn(stackId)?.region }); + const describe = await cf.describeStackResources({ PhysicalResourceId: distId }).promise(); + if (!checkSuccessOrLogResponse(describe.$response.httpResponse)) { + throw new Error('unable to call describeStackResources on distribution id'); + } + const found = describe.StackResources?.find(e => e.ResourceType === 'AWS::CloudFront::Distribution' && e.StackId === stackId); + return found?.LogicalResourceId ?? null; +} +async function processArns(uniqueSid, distribution, arnsRO, arnsRW, deleteOnly, tagNameRO, tagNameRW) { + for (const dryRun of [true, false]) { + const pairWith = (b) => ((e) => [e, b]); + const mapped = arnsRO.map(pairWith(false)).concat(arnsRW.map(pairWith(true))); + for (const [arn, writeAccess] of mapped) { + console.log('processing ' + arn + (writeAccess ? ' (read-write)' : ' (read-only)') + (dryRun ? ' [DRY RUN]' : '')); + const arnParts = parseArn(arn); + if (!arnParts) { + throw new Error('unparseable arn ' + arn); + } + const arnResource = arnParts.resource ?? ''; + const safetyCheckTag = writeAccess ? + ((k) => k === tagNameRW) : + ((k) => k === tagNameRW || k === tagNameRO); + if (arnParts.service === 's3' && arnResource.length > 0 && !arnResource.includes('/')) { + const s3tags = await s3.getBucketTagging({ Bucket: arnResource }).promise(); + if (!checkSuccessOrLogResponse(s3tags.$response.httpResponse)) { + throw new Error('unable to verify distribution safety-check tag for ' + arn); + } + const foundtag = s3tags?.TagSet?.map(e => e.Key)?.find(safetyCheckTag); + if (!foundtag) { + throw new Error('no matching distribution safety-check tag for ' + arn); + } + console.log('verified distribution safety-check tag ' + foundtag + ' for ' + arn); + const desired = { + Sid: uniqueSid, + Effect: 'Allow', + Principal: { Service: 'cloudfront.amazonaws.com' }, + Action: writeAccess ? ['s3:GetObject', 's3:PutObject'] : 's3:GetObject', + Resource: arn + '/*', + Condition: { StringEquals: { 'aws:SourceArn': distribution } }, + }; + const get = await s3.getBucketPolicy({ Bucket: arnResource }).promise(); + const parsed = parsePolicyJSON(get.Policy, arn); + if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { + const put = await s3.putBucketPolicy({ Bucket: arnResource, Policy: JSON.stringify(parsed) }).promise(); + if (!checkSuccessOrLogResponse(put.$response.httpResponse)) { + throw new Error('unable to put new JSON policy document for ' + arn); + } + console.log('successfully modified ' + arn); + } + } + else if (arnParts.service === 'kms' && arnParts.region && arnResource.startsWith('key/')) { + const kms = getKMSForRegion(arnParts.region); + for (let marker = undefined;;) { + const kmstags = await kms.listResourceTags({ KeyId: arn, Marker: marker }).promise(); + if (!checkSuccessOrLogResponse(kmstags.$response.httpResponse)) { + throw new Error('unable to verify distribution safety-check tag for ' + arn); + } + const foundkey = kmstags.Tags?.map(e => e.TagKey)?.find(safetyCheckTag); + if (foundkey) { + console.log('verified distribution safety-check tag ' + foundkey + ' for ' + arn); + break; + } + if (!kmstags.Truncated || !kmstags.NextMarker) { + throw new Error('no matching distribution safety-check tag for ' + arn); + } + } + const desired = { + Sid: uniqueSid, + Effect: 'Allow', + Principal: { Service: 'cloudfront.amazonaws.com' }, + Action: writeAccess ? ['kms:Decrypt', 'kms:Encrypt', 'kms:GetDataKey*'] : 'kms:Decrypt', + Resource: arn, + Condition: { StringEquals: { 'aws:SourceArn': distribution } }, + }; + const get = await kms.getKeyPolicy({ KeyId: arn, PolicyName: 'default' }).promise(); + const parsed = parsePolicyJSON(get.Policy, arn); + if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { + const put = await kms.putKeyPolicy({ KeyId: arn, PolicyName: 'default', Policy: JSON.stringify(parsed) }).promise(); + if (!checkSuccessOrLogResponse(put.$response.httpResponse)) { + throw new Error('unable to put new JSON policy document for ' + arn); + } + console.log('successfully modified ' + arn); + } + } + else { + throw new Error('unknown service for ' + arn); + } + } + } +} +async function handler(event) { + function isStringArray(x) { + return Array.isArray(x) && x.every(e => typeof e === 'string'); + } + const dist = event.ResourceProperties.distribution; + const arnsRO = event.ResourceProperties.readOnlyArns; + const arnsRW = event.ResourceProperties.readWriteArns; + if (typeof dist !== 'string' || !dist.startsWith('arn:aws:cloudfront:')) { + throw new Error('invalid distribution property'); + } + if (!isStringArray(arnsRO) || !arnsRO.every(parseArn)) { + throw new Error('invalid readOnlyArns property'); + } + if (!isStringArray(arnsRW) || !arnsRW.every(parseArn)) { + throw new Error('invalid readWriteArns property'); + } + const account = parseArn(event.ServiceToken)?.account; + if (!account || parseArn(dist)?.account !== account) { + throw new Error('invalid cross-account permission grant'); + } + let physicalId = String(event.PhysicalResourceId ?? generatePhysicalResourceId()); + // If updating and params have changed, replace the physical ID + // to trigger a CloudFormation Delete request for the previous ID + // when (and if) the update succeeds - a safe two-phase commit. + if (event.RequestType === 'Update') { + const update = event; + const olddist = update.OldResourceProperties.distribution ?? ''; + const oldarnsRO = update.OldResourceProperties.readOnlyArns ?? []; + const oldarnsRW = update.OldResourceProperties.readWriteArns ?? []; + if (JSON.stringify([dist, arnsRO, arnsRW]) !== JSON.stringify([olddist, oldarnsRO, oldarnsRW])) { + console.log('parameters changed, generating new physical id'); + physicalId = generatePhysicalResourceId(); + } + } + // Look up logical ID from distribution ID, verify against our stack ID + const distLogicalId = await lookupDistributionLogicalIdFromArn(dist, event.StackId); + if (!distLogicalId) { + throw new Error('unable to locate distribution in stack'); + } + // NOTE: This logic must be duplicated exactly from computeSafetyCheckTagName + const safetyCheckText = process.env.CDK_STACK_NAME + '|' + distLogicalId; + const safetyCheckHash = (0, crypto_1.createHash)('sha256').update(safetyCheckText).digest('hex').slice(-32); + const tagNameRO = `aws-cdk:grant-distribution-ro:${safetyCheckHash}`; + const tagNameRW = `aws-cdk:grant-distribution-rw:${safetyCheckHash}`; + const dedupeSet = new Set(); + const hasNeverSeen = (e) => !dedupeSet.has(e) && !!dedupeSet.add(e); + // Process arnsRW first in case an ARN appears in both arnsRW and arnsRO + const dedupedRW = arnsRW.filter(hasNeverSeen); + const dedupedRO = arnsRO.filter(hasNeverSeen); + const policySid = generatePolicySid(physicalId); + const deleteOnly = event.RequestType === 'Delete'; + await processArns(policySid, dist, dedupedRO, dedupedRW, deleteOnly, tagNameRO, tagNameRW); + return { + PhysicalResourceId: physicalId, + }; +} +exports.handler = handler; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0Isc0RBQXNEO0FBQ3RELG1DQUFnRDtBQUNoRCxxQ0FBZ0U7QUFFaEUsbUVBQW1FO0FBQ25FLE1BQU0sRUFBRSxHQUFHLElBQUksWUFBRSxFQUFFLENBQUM7QUFFcEIsbUVBQW1FO0FBQ25FLE1BQU0sZUFBZSxHQUFHLENBQUMsR0FBRyxFQUFFO0lBQzVCLElBQUksR0FBb0IsQ0FBQztJQUN6QixPQUFPLENBQUMsTUFBYyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxNQUFNLEVBQUU7WUFDeEMsR0FBRyxHQUFHLElBQUksYUFBRyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztTQUMzQjtRQUNELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQXdCTCxTQUFTLHlCQUF5QixDQUFDLElBQXFDO0lBQ3RFLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksR0FBRyxFQUFFO1FBQzVELE9BQU8sSUFBSSxDQUFDO0tBQ2I7SUFDRCxJQUFJLElBQUksRUFBRTtRQUNSLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0tBQ25DO1NBQU07UUFDTCxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixDQUFDLENBQUM7S0FDbkM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxTQUFTLDBCQUEwQjtJ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QUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDOUMsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUU5QyxNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNoRCxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsQ0FBQztJQUNsRCxNQUFNLFdBQVcsQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUUzRixPQUFPO1FBQ0wsa0JBQWtCLEVBQUUsVUFBVTtLQUMvQixDQUFDO0FBQ0osQ0FBQztBQWpFRCwwQkFpRUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG4vKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXMgKi9cbmltcG9ydCB7IGNyZWF0ZUhhc2gsIHJhbmRvbVVVSUQgfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgQ2xvdWRGb3JtYXRpb24sIEh0dHBSZXNwb25zZSwgS01TLCBTMyB9IGZyb20gJ2F3cy1zZGsnO1xuXG4vLyBTMyBoYW5kbGVzIGNyb3NzLXJlZ2lvbiByZWRpcmVjdGlvbiwgY2FuIHVzZSBhIGdsb2JhbCBBUEkgb2JqZWN0XG5jb25zdCBzMyA9IG5ldyBTMygpO1xuXG4vLyBLTVMgZG9lcyBub3QgcmVkaXJlY3QgYWNyb3NzIHJlZ2lvbnMsIHJlcXVpcmVzIGEgcmVnaW9uYWwgZ2V0dGVyXG5jb25zdCBnZXRLTVNGb3JSZWdpb24gPSAoKCkgPT4ge1xuICBsZXQga21zOiBLTVMgfCB1bmRlZmluZWQ7XG4gIHJldHVybiAocmVnaW9uOiBzdHJpbmcpID0+IHtcbiAgICBpZiAoIWttcyB8fCBrbXMuY29uZmlnLnJlZ2lvbiAhPT0gcmVnaW9uKSB7XG4gICAgICBrbXMgPSBuZXcgS01TKHsgcmVnaW9uIH0pO1xuICAgIH1cbiAgICByZXR1cm4ga21zO1xuICB9O1xufSkoKTtcblxuLy8gV2UgYXJlIG5vdCB0cnlpbmcgdG8gZG8gYSBjb21wbGV0ZSBwYXJzZSBvZiB0aGUgUG9saWN5IGZpZWxkcztcbi8vIHdlIG9ubHkgdmVyaWZ5IGVub3VnaCBvZiB0aGUgdHlwZSB0byBzYWZlbHkgbWFrZSBtb2RpZmljYXRpb25zLlxuaW50ZXJmYWNlIEJhcmVNaW5pbXVtU3RhdGVtZW50IHtcbiAgU2lkPzogc3RyaW5nO1xuICBba2V5OiBzdHJpbmddOiBhbnk7XG59XG5pbnRlcmZhY2UgQmFyZU1pbmltdW1Qb2xpY3kge1xuICBWZXJzaW9uOiBzdHJpbmc7XG4gIFN0YXRlbWVudDogQmFyZU1pbmltdW1TdGF0ZW1lbnRbXTtcbiAgW2tleTogc3RyaW5nXTogYW55O1xufVxuXG4vLyBXZSBhcmUgYSBsb3Qgc3RyaWN0ZXIgYWJvdXQgb3VyIG93biBnZW5lcmF0ZWQgc3RhdGVtZW50c1xuaW50ZXJmYWNlIFBlcm1pc3Npb25HcmFudFN0YXRlbWVudCB7XG4gIFNpZDogc3RyaW5nO1xuICBFZmZlY3Q6ICdBbGxvdyc7XG4gIFByaW5jaXBhbDogeyBTZXJ2aWNlOiAnY2xvdWRmcm9udC5hbWF6b25hd3MuY29tJyB9O1xuICBBY3Rpb246IHN0cmluZyB8IHN0cmluZ1tdO1xuICBSZXNvdXJjZTogc3RyaW5nIHwgc3RyaW5nW107XG4gIENvbmRpdGlvbjogeyBTdHJpbmdFcXVhbHM6IHsgJ2F3czpTb3VyY2VBcm4nOiBzdHJpbmcgfSB9O1xufVxuXG5mdW5jdGlvbiBjaGVja1N1Y2Nlc3NPckxvZ1Jlc3BvbnNlKHJlc3A6IEh0dHBSZXNwb25zZSB8IHVuZGVmaW5lZCB8IG51bGwpIHtcbiAgaWYgKHJlc3AgJiYgcmVzcC5zdGF0dXNDb2RlID49IDIwMCAmJiByZXNwLnN0YXR1c0NvZGUgPD0gMjk5KSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgaWYgKHJlc3ApIHtcbiAgICBjb25zb2xlLmxvZyhgRVJST1I6ICR7cmVzcC5zdGF0dXNDb2RlfSAke3Jlc3Auc3RhdHVzTWVzc2FnZX1gKTtcbiAgICBjb25zb2xlLmxvZyhyZXNwLmJvZHkudG9TdHJpbmcoKSk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coJ0VSUk9SOiBubyByZXNwb25zZScpO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVQaHlzaWNhbFJlc291cmNlSWQoKSB7XG4gIHJldHVybiAnYXdzY2RrOmRpc3RyaWJ1dGlvbi1wb2xpY3ktc2V0dGVyOicgKyByYW5kb21VVUlEKCkucmVwbGFjZSgnLScsICcnKTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVQb2xpY3lTaWQocGh5c2ljYWxSZXNvdXJjZUlkOiBzdHJpbmcpIHtcbiAgY29uc3QgaGFzaCA9IHBoeXNpY2FsUmVzb3VyY2VJZC5zcGxpdCgnOicpLmF0KC0xKTtcbiAgcmV0dXJuICdDREtEaXN0cmlidXRpb25Qb2xpY3lTZXR0ZXInICsgaGFzaD8udG9VcHBlckNhc2UoKTtcbn1cblxuaW50ZXJmYWNlIFBhcnNlZEFybiB7XG4gIHBhcnRpdGlvbj86IHN0cmluZztcbiAgc2VydmljZT86IHN0cmluZztcbiAgcmVnaW9uPzogc3RyaW5nO1xuICBhY2NvdW50Pzogc3RyaW5nLFxuICByZXNvdXJjZT86IHN0cmluZztcbn1cbmZ1bmN0aW9uIHBhcnNlQXJuKGFybjogc3RyaW5nKSA6IFBhcnNlZEFybiB8IG51bGwge1xuICBjb25zdCByZSA9IC9eYXJuOig/PHBhcnRpdGlvbj5bXjpdKyk/Oig/PHNlcnZpY2U+W146XSspPzooPzxyZWdpb24+W146XSspPzooPzxhY2NvdW50PlteOl0rKT86KD88cmVzb3VyY2U+LispPyQvO1xuICByZXR1cm4gYXJuLm1hdGNoKHJlKT8uZ3JvdXBzID8/IG51bGw7XG59XG5cbi8vIHBhcnNlcyBKU09OIGludG8gYSBCYXJlTWluaW11bVBvbGljeSwgb3IgdGhyb3dzIGFuIGVycm9yXG5mdW5jdGlvbiBwYXJzZVBvbGljeUpTT04oc3RyOiBzdHJpbmcgfCB1bmRlZmluZWQsIGNvbnRleHQ6IHN0cmluZykge1xuICBpZiAoIXN0cikge1xuICAgIHRocm93IG5ldyBFcnJvcigndW5hYmxlIHRvIGZldGNoIHBvbGljeSBkb2N1bWVudCBmb3IgJyArIGNvbnRleHQpO1xuICB9XG4gIGxldCBwYXJzZWQ6IGFueTtcbiAgdHJ5IHtcbiAgICBwYXJzZWQgPSBKU09OLnBhcnNlKHN0cik7XG4gIH0gY2F0Y2gge1xuICAgIHRocm93IG5ldyBFcnJvcigndW5hYmxlIHRvIHBhcnNlIEpTT04gcG9saWN5IGRvY3VtZW50IGZvciAnICsgY29udGV4dCk7XG4gIH1cbiAgLy8gVG8gbWFpbnRhaW4gYSBnb29kIGNoYW5jZSBvZiBmb3J3YXJkLWNvbXBhdGliaWxpdHksIHRoaXMgaXMgYSBsb29zZSBjaGVjazpcbiAgLy8gVmVyc2lvbiBleGlzdHMgYW5kIGlzIG5vdCB0b28gb2xkIGZvciB2YWx1ZSByZWZlcmVuY2VzLCBhbmQgU3RhdGVtZW50cyBpcyBhblxuICAvLyBhcnJheSBvZiBvYmplY3RzIGVhY2ggb2Ygd2hpY2ggaGFzIGFuIEVmZmVjdCBzdHJpbmcgYW5kIG1heWJlIGEgU2lkIHN0cmluZy5cbiAgaWYgKHR5cGVvZiBwYXJzZWQgIT09ICdvYmplY3QnIHx8IHR5cGVvZiBwYXJzZWQuVmVyc2lvbiAhPT0gJ3N0cmluZycgfHxcbiAgICAgIHBhcnNlZC5WZXJzaW9uLmxlbmd0aCAhPSAxMCB8fCBwYXJzZWQuVmVyc2lvbiA9PT0gJzIwMDgtMTAtMTcnIHx8XG4gICAgICAhQXJyYXkuaXNBcnJheShwYXJzZWQuU3RhdGVtZW50KSApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgSlNPTiBwb2xpY3kgZG9jdW1lbnQgZm9yICcgKyBjb250ZXh0KTtcbiAgfVxuICBmb3IgKGNvbnN0IHMgb2YgcGFyc2VkLlN0YXRlbWVudCkge1xuICAgIGlmICh0eXBlb2YgcyAhPT0gJ29iamVjdCcgfHwgISgnRWZmZWN0JyBpbiBzKSB8fCB0eXBlb2Ygcy5FZmZlY3QgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgSlNPTiBwb2xpY3kgc3RhdGVtZW50IGZvciAnICsgY29udGV4dCk7XG4gICAgfVxuICAgIGlmICgnU2lkJyBpbiBzICYmIHR5cGVvZiBzLlNpZCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBKU09OIHBvbGljeSBzdGF0ZW1lbnQgZm9yICcgKyBjb250ZXh0KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHBhcnNlZCBhcyBCYXJlTWluaW11bVBvbGljeTtcbn1cblxuLy8gcmVwbGFjZSBwcm9wZXJ0aWVzIG9mIG9uZSBTdGF0ZW1lbnQgd2l0aCBhbm90aGVyOyByZXR1cm5zIGZhbHNlIGlmIG5vdGhpbmcgY2hhbmdlZFxuZnVuY3Rpb24gcmVwbGFjZVByb3BlcnRpZXNXaXRoKGRzdDogQmFyZU1pbmltdW1TdGF0ZW1lbnQsIHNyYzogQmFyZU1pbmltdW1TdGF0ZW1lbnQpIHtcbiAgbGV0IGRpZEFueXRoaW5nID0gZmFsc2U7XG4gIGZvciAoY29uc3QgayBpbiBkc3QpIHtcbiAgICBpZiAoIShrIGluIHNyYykpIHtcbiAgICAgIGRlbGV0ZSBkc3Rba107XG4gICAgICBkaWRBbnl0aGluZyA9IHRydWU7XG4gICAgfVxuICB9XG4gIGZvciAoY29uc3QgayBpbiBzcmMpIHtcbiAgICBpZiAoIShrIGluIGRzdCkgfHwgSlNPTi5zdHJpbmdpZnkoZHN0W2tdKSAhPT0gSlNPTi5zdHJpbmdpZnkoc3JjW2tdKSkge1xuICAgICAgZHN0W2tdID0gc3JjW2tdO1xuICAgICAgZGlkQW55dGhpbmcgPSB0cnVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZGlkQW55dGhpbmc7XG59XG5cbi8vIG1vZGlmaWVzIGFycmF5IGluIHBsYWNlOyByZXR1cm5zIGZhbHNlIGlmIG5vIGNoYW5nZXMgd2VyZSBtYWRlIHRvIHN0YXRlbWVudHNcbmZ1bmN0aW9uIGFkZE9yUmVwbGFjZVBvbGljeVN0YXRlbWVudChcbiAgczogQmFyZU1pbmltdW1TdGF0ZW1lbnRbXSxcbiAgZGVzaXJlZDogQmFyZU1pbmltdW1TdGF0ZW1lbnQgJiBQZXJtaXNzaW9uR3JhbnRTdGF0ZW1lbnQsXG4gIGRlbGV0ZU9ubHk6IGJvb2xlYW4sXG4gIGNvbnRleHQ6IHN0cmluZyxcbikge1xuICBjb25zdCBmb3VuZCA9IHMubWFwKChfLCBpKSA9PiBpKS5maWx0ZXIoaSA9PiBzW2ldLlNpZCA9PT0gZGVzaXJlZC5TaWQpO1xuICBpZiAoZm91bmQubGVuZ3RoID4gMSkge1xuICAgIHRocm93IG5ldyBFcnJvcignZHVwbGljYXRlIFNpZCBpbiBKU09OIHBvbGljeSBkb2N1bWVudCBmb3IgJyArIGNvbnRleHQpO1xuICB9XG4gIGlmIChkZWxldGVPbmx5KSB7XG4gICAgaWYgKGZvdW5kLmxlbmd0aCA9PSAxKSB7XG4gICAgICBzLnNwbGljZShmb3VuZFswXSwgMSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBpZiAoZm91bmQubGVuZ3RoID09IDEpIHtcbiAgICAgIHJldHVybiByZXBsYWNlUHJvcGVydGllc1dpdGgoc1tmb3VuZFswXV0sIGRlc2lyZWQpO1xuICAgIH1cbiAgICBzLnB1c2goZGVzaXJlZCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gbG9va3VwRGlzdHJpYnV0aW9uTG9naWNhbElkRnJvbUFybihkaXN0QXJuOiBzdHJpbmcsIHN0YWNrSWQ6IHN0cmluZykge1xuICBjb25zdCBkaXN0SWQgPSBkaXN0QXJuLnNwbGl0KCdkaXN0cmlidXRpb24vJykuYXQoLTEpO1xuICBpZiAoIWRpc3RJZCB8fCAhZGlzdElkLm1hdGNoKC9eWzAtOUEtWl0rJC8pKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGRpc3RyaWJ1dGlvbiBhcm4gJyArIGRpc3RBcm4pO1xuICB9XG4gIGNvbnN0IGNmID0gbmV3IENsb3VkRm9ybWF0aW9uKHsgYXBpVmVyc2lvbjogJzIwMTAtMDUtMTUnLCByZWdpb246IHBhcnNlQXJuKHN0YWNrSWQpPy5yZWdpb24gfSk7XG4gIGNvbnN0IGRlc2NyaWJlID0gYXdhaXQgY2YuZGVzY3JpYmVTdGFja1Jlc291cmNlcyh7IFBoeXNpY2FsUmVzb3VyY2VJZDogZGlzdElkIH0pLnByb21pc2UoKTtcbiAgaWYgKCFjaGVja1N1Y2Nlc3NPckxvZ1Jlc3BvbnNlKGRlc2NyaWJlLiRyZXNwb25zZS5odHRwUmVzcG9uc2UpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCd1bmFibGUgdG8gY2FsbCBkZXNjcmliZVN0YWNrUmVzb3VyY2VzIG9uIGRpc3RyaWJ1dGlvbiBpZCcpO1xuICB9XG4gIGNvbnN0IGZvdW5kID0gZGVzY3JpYmUuU3RhY2tSZXNvdXJjZXM/LmZpbmQoXG4gICAgZSA9PiBlLlJlc291cmNlVHlwZSA9PT0gJ0FXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uJyAmJiBlLlN0YWNrSWQgPT09IHN0YWNrSWQsXG4gICk7XG4gIHJldHVybiBmb3VuZD8uTG9naWNhbFJlc291cmNlSWQgPz8gbnVsbDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0FybnMoXG4gIHVuaXF1ZVNpZDogc3RyaW5nLFxuICBkaXN0cmlidXRpb246IHN0cmluZyxcbiAgYXJuc1JPOiBzdHJpbmdbXSxcbiAgYXJuc1JXOiBzdHJpbmdbXSxcbiAgZGVsZXRlT25seTogYm9vbGVhbixcbiAgdGFnTmFtZVJPOiBzdHJpbmcsXG4gIHRhZ05hbWVSVzogc3RyaW5nLFxuKSB7XG4gIGZvciAoY29uc3QgZHJ5UnVuIG9mIFt0cnVlLCBmYWxzZV0pIHtcbiAgICBjb25zdCBwYWlyV2l0aCA9IChiOmJvb2xlYW4pID0+ICgoZTogc3RyaW5nKTogW3N0cmluZywgYm9vbGVhbl0gPT4gW2UsIGJdKTtcbiAgICBjb25zdCBtYXBwZWQgPSBhcm5zUk8ubWFwKHBhaXJXaXRoKGZhbHNlKSkuY29uY2F0KGFybnNSVy5tYXAocGFpcldpdGgodHJ1ZSkpKTtcbiAgICBmb3IgKGNvbnN0IFthcm4sIHdyaXRlQWNjZXNzXSBvZiBtYXBwZWQpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdwcm9jZXNzaW5nICcgKyBhcm4gKyAod3JpdGVBY2Nlc3MgPyAnIChyZWFkLXdyaXRlKScgOiAnIChyZWFkLW9ubHkpJykgKyAoZHJ5UnVuID8gJyBbRFJZIFJVTl0nIDogJycpKTtcblxuICAgICAgY29uc3QgYXJuUGFydHMgPSBwYXJzZUFybihhcm4pO1xuICAgICAgaWYgKCFhcm5QYXJ0cykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VucGFyc2VhYmxlIGFybiAnICsgYXJuKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGFyblJlc291cmNlID0gYXJuUGFydHMucmVzb3VyY2UgPz8gJyc7XG5cbiAgICAgIGNvbnN0IHNhZmV0eUNoZWNrVGFnID0gd3JpdGVBY2Nlc3MgP1xuICAgICAgICAoKGs6IHN0cmluZykgPT4gayA9PT0gdGFnTmFtZVJXKSA6XG4gICAgICAgICgoazogc3RyaW5nKSA9PiBrID09PSB0YWdOYW1lUlcgfHwgayA9PT0gdGFnTmFtZVJPKTtcblxuICAgICAgaWYgKGFyblBhcnRzLnNlcnZpY2UgPT09ICdzMycgJiYgYXJuUmVzb3VyY2UubGVuZ3RoID4gMCAmJiAhYXJuUmVzb3VyY2UuaW5jbHVkZXMoJy8nKSkge1xuICAgICAgICBjb25zdCBzM3RhZ3MgPSBhd2FpdCBzMy5nZXRCdWNrZXRUYWdnaW5nKHsgQnVja2V0OiBhcm5SZXNvdXJjZSB9KS5wcm9taXNlKCk7XG4gICAgICAgIGlmICghY2hlY2tTdWNjZXNzT3JMb2dSZXNwb25zZShzM3RhZ3MuJHJlc3BvbnNlLmh0dHBSZXNwb25zZSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuYWJsZSB0byB2ZXJpZnkgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgZm9yICcgKyBhcm4pO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGZvdW5kdGFnID0gczN0YWdzPy5UYWdTZXQ/Lm1hcChlID0+IGUuS2V5KT8uZmluZChzYWZldHlDaGVja1RhZyk7XG4gICAgICAgIGlmICghZm91bmR0YWcpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vIG1hdGNoaW5nIGRpc3RyaWJ1dGlvbiBzYWZldHktY2hlY2sgdGFnIGZvciAnICsgYXJuKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZygndmVyaWZpZWQgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgJyArIGZvdW5kdGFnICsgJyBmb3IgJyArIGFybik7XG5cbiAgICAgICAgY29uc3QgZGVzaXJlZDogUGVybWlzc2lvbkdyYW50U3RhdGVtZW50ID0ge1xuICAgICAgICAgIFNpZDogdW5pcXVlU2lkLFxuICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICBQcmluY2lwYWw6IHsgU2VydmljZTogJ2Nsb3VkZnJvbnQuYW1hem9uYXdzLmNvbScgfSxcbiAgICAgICAgICBBY3Rpb246IHdyaXRlQWNjZXNzID8gWydzMzpHZXRPYmplY3QnLCAnczM6UHV0T2JqZWN0J10gOiAnczM6R2V0T2JqZWN0JyxcbiAgICAgICAgICBSZXNvdXJjZTogYXJuICsgJy8qJyxcbiAgICAgICAgICBDb25kaXRpb246IHsgU3RyaW5nRXF1YWxzOiB7ICdhd3M6U291cmNlQXJuJzogZGlzdHJpYnV0aW9uIH0gfSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgZ2V0ID0gYXdhaXQgczMuZ2V0QnVja2V0UG9saWN5KHsgQnVja2V0OiBhcm5SZXNvdXJjZSB9KS5wcm9taXNlKCk7XG4gICAgICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlUG9saWN5SlNPTihnZXQuUG9saWN5LCBhcm4pO1xuICAgICAgICBpZiAoYWRkT3JSZXBsYWNlUG9saWN5U3RhdGVtZW50KHBhcnNlZC5TdGF0ZW1lbnQsIGRlc2lyZWQsIGRlbGV0ZU9ubHksIGFybikgJiYgIWRyeVJ1bikge1xuICAgICAgICAgIGNvbnN0IHB1dCA9IGF3YWl0IHMzLnB1dEJ1Y2tldFBvbGljeSh7IEJ1Y2tldDogYXJuUmVzb3VyY2UsIFBvbGljeTogSlNPTi5zdHJpbmdpZnkocGFyc2VkKSB9KS5wcm9taXNlKCk7XG4gICAgICAgICAgaWYgKCFjaGVja1N1Y2Nlc3NPckxvZ1Jlc3BvbnNlKHB1dC4kcmVzcG9uc2UuaHR0cFJlc3BvbnNlKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmFibGUgdG8gcHV0IG5ldyBKU09OIHBvbGljeSBkb2N1bWVudCBmb3IgJyArIGFybik7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnNvbGUubG9nKCdzdWNjZXNzZnVsbHkgbW9kaWZpZWQgJyArIGFybik7XG4gICAgICAgIH1cblxuICAgICAgfSBlbHNlIGlmIChhcm5QYXJ0cy5zZXJ2aWNlID09PSAna21zJyAmJiBhcm5QYXJ0cy5yZWdpb24gJiYgYXJuUmVzb3VyY2Uuc3RhcnRzV2l0aCgna2V5LycpKSB7XG4gICAgICAgIGNvbnN0IGttcyA9IGdldEtNU0ZvclJlZ2lvbihhcm5QYXJ0cy5yZWdpb24pO1xuXG4gICAgICAgIGZvciAobGV0IG1hcmtlciA9IHVuZGVmaW5lZDs7KSB7XG4gICAgICAgICAgY29uc3Qga21zdGFncyA9IGF3YWl0IGttcy5saXN0UmVzb3VyY2VUYWdzKHsgS2V5SWQ6IGFybiwgTWFya2VyOiBtYXJrZXIgfSkucHJvbWlzZSgpO1xuICAgICAgICAgIGlmICghY2hlY2tTdWNjZXNzT3JMb2dSZXNwb25zZShrbXN0YWdzLiRyZXNwb25zZS5odHRwUmVzcG9uc2UpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuYWJsZSB0byB2ZXJpZnkgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgZm9yICcgKyBhcm4pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBmb3VuZGtleSA9IGttc3RhZ3MuVGFncz8ubWFwKGUgPT4gZS5UYWdLZXkpPy5maW5kKHNhZmV0eUNoZWNrVGFnKTtcbiAgICAgICAgICBpZiAoZm91bmRrZXkpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCd2ZXJpZmllZCBkaXN0cmlidXRpb24gc2FmZXR5LWNoZWNrIHRhZyAnICsgZm91bmRrZXkgKyAnIGZvciAnICsgYXJuKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoIWttc3RhZ3MuVHJ1bmNhdGVkIHx8ICFrbXN0YWdzLk5leHRNYXJrZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm8gbWF0Y2hpbmcgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgZm9yICcgKyBhcm4pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRlc2lyZWQ6IFBlcm1pc3Npb25HcmFudFN0YXRlbWVudCA9IHtcbiAgICAgICAgICBTaWQ6IHVuaXF1ZVNpZCxcbiAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgUHJpbmNpcGFsOiB7IFNlcnZpY2U6ICdjbG91ZGZyb250LmFtYXpvbmF3cy5jb20nIH0sXG4gICAgICAgICAgQWN0aW9uOiB3cml0ZUFjY2VzcyA/IFsna21zOkRlY3J5cHQnLCAna21zOkVuY3J5cHQnLCAna21zOkdldERhdGFLZXkqJ10gOiAna21zOkRlY3J5cHQnLFxuICAgICAgICAgIFJlc291cmNlOiBhcm4sXG4gICAgICAgICAgQ29uZGl0aW9uOiB7IFN0cmluZ0VxdWFsczogeyAnYXdzOlNvdXJjZUFybic6IGRpc3RyaWJ1dGlvbiB9IH0sXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGdldCA9IGF3YWl0IGttcy5nZXRLZXlQb2xpY3koeyBLZXlJZDogYXJuLCBQb2xpY3lOYW1lOiAnZGVmYXVsdCcgfSkucHJvbWlzZSgpO1xuICAgICAgICBjb25zdCBwYXJzZWQgPSBwYXJzZVBvbGljeUpTT04oZ2V0LlBvbGljeSwgYXJuKTtcbiAgICAgICAgaWYgKGFkZE9yUmVwbGFjZVBvbGljeVN0YXRlbWVudChwYXJzZWQuU3RhdGVtZW50LCBkZXNpcmVkLCBkZWxldGVPbmx5LCBhcm4pICYmICFkcnlSdW4pIHtcbiAgICAgICAgICBjb25zdCBwdXQgPSBhd2FpdCBrbXMucHV0S2V5UG9saWN5KHsgS2V5SWQ6IGFybiwgUG9saWN5TmFtZTogJ2RlZmF1bHQnLCBQb2xpY3k6IEpTT04uc3RyaW5naWZ5KHBhcnNlZCkgfSkucHJvbWlzZSgpO1xuICAgICAgICAgIGlmICghY2hlY2tTdWNjZXNzT3JMb2dSZXNwb25zZShwdXQuJHJlc3BvbnNlLmh0dHBSZXNwb25zZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndW5hYmxlIHRvIHB1dCBuZXcgSlNPTiBwb2xpY3kgZG9jdW1lbnQgZm9yICcgKyBhcm4pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zb2xlLmxvZygnc3VjY2Vzc2Z1bGx5IG1vZGlmaWVkICcgKyBhcm4pO1xuICAgICAgICB9XG5cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndW5rbm93biBzZXJ2aWNlIGZvciAnICsgYXJuKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQpIHtcblxuICBmdW5jdGlvbiBpc1N0cmluZ0FycmF5KHg6IGFueSkgOiB4IGlzIHN0cmluZ1tdIHtcbiAgICByZXR1cm4gQXJyYXkuaXNBcnJheSh4KSAmJiB4LmV2ZXJ5KGUgPT4gdHlwZW9mIGUgPT09ICdzdHJpbmcnKTtcbiAgfVxuXG4gIGNvbnN0IGRpc3QgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuZGlzdHJpYnV0aW9uO1xuICBjb25zdCBhcm5zUk8gPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMucmVhZE9ubHlBcm5zO1xuICBjb25zdCBhcm5zUlcgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMucmVhZFdyaXRlQXJucztcbiAgaWYgKHR5cGVvZiBkaXN0ICE9PSAnc3RyaW5nJyB8fCAhZGlzdC5zdGFydHNXaXRoKCdhcm46YXdzOmNsb3VkZnJvbnQ6JykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgZGlzdHJpYnV0aW9uIHByb3BlcnR5Jyk7XG4gIH1cbiAgaWYgKCFpc1N0cmluZ0FycmF5KGFybnNSTykgfHwgIWFybnNSTy5ldmVyeShwYXJzZUFybikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgcmVhZE9ubHlBcm5zIHByb3BlcnR5Jyk7XG4gIH1cbiAgaWYgKCFpc1N0cmluZ0FycmF5KGFybnNSVykgfHwgIWFybnNSVy5ldmVyeShwYXJzZUFybikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgcmVhZFdyaXRlQXJucyBwcm9wZXJ0eScpO1xuICB9XG5cbiAgY29uc3QgYWNjb3VudCA9IHBhcnNlQXJuKGV2ZW50LlNlcnZpY2VUb2tlbik/LmFjY291bnQ7XG4gIGlmICghYWNjb3VudCB8fCBwYXJzZUFybihkaXN0KT8uYWNjb3VudCAhPT0gYWNjb3VudCkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBjcm9zcy1hY2NvdW50IHBlcm1pc3Npb24gZ3JhbnQnKTtcbiAgfVxuXG4gIGxldCBwaHlzaWNhbElkID0gU3RyaW5nKChldmVudCBhcyBhbnkpLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBnZW5lcmF0ZVBoeXNpY2FsUmVzb3VyY2VJZCgpKTtcblxuICAvLyBJZiB1cGRhdGluZyBhbmQgcGFyYW1zIGhhdmUgY2hhbmdlZCwgcmVwbGFjZSB0aGUgcGh5c2ljYWwgSURcbiAgLy8gdG8gdHJpZ2dlciBhIENsb3VkRm9ybWF0aW9uIERlbGV0ZSByZXF1ZXN0IGZvciB0aGUgcHJldmlvdXMgSURcbiAgLy8gd2hlbiAoYW5kIGlmKSB0aGUgdXBkYXRlIHN1Y2NlZWRzIC0gYSBzYWZlIHR3by1waGFzZSBjb21taXQuXG4gIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ1VwZGF0ZScpIHtcbiAgICBjb25zdCB1cGRhdGUgPSBldmVudCBhcyBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVVwZGF0ZUV2ZW50O1xuICAgIGNvbnN0IG9sZGRpc3QgPSB1cGRhdGUuT2xkUmVzb3VyY2VQcm9wZXJ0aWVzLmRpc3RyaWJ1dGlvbiA/PyAnJztcbiAgICBjb25zdCBvbGRhcm5zUk8gPSB1cGRhdGUuT2xkUmVzb3VyY2VQcm9wZXJ0aWVzLnJlYWRPbmx5QXJucyA/PyBbXTtcbiAgICBjb25zdCBvbGRhcm5zUlcgPSB1cGRhdGUuT2xkUmVzb3VyY2VQcm9wZXJ0aWVzLnJlYWRXcml0ZUFybnMgPz8gW107XG4gICAgaWYgKEpTT04uc3RyaW5naWZ5KFtkaXN0LCBhcm5zUk8sIGFybnNSV10pICE9PSBKU09OLnN0cmluZ2lmeShbb2xkZGlzdCwgb2xkYXJuc1JPLCBvbGRhcm5zUlddKSkge1xuICAgICAgY29uc29sZS5sb2coJ3BhcmFtZXRlcnMgY2hhbmdlZCwgZ2VuZXJhdGluZyBuZXcgcGh5c2ljYWwgaWQnKTtcbiAgICAgIHBoeXNpY2FsSWQgPSBnZW5lcmF0ZVBoeXNpY2FsUmVzb3VyY2VJZCgpO1xuICAgIH1cbiAgfVxuXG4gIC8vIExvb2sgdXAgbG9naWNhbCBJRCBmcm9tIGRpc3RyaWJ1dGlvbiBJRCwgdmVyaWZ5IGFnYWluc3Qgb3VyIHN0YWNrIElEXG4gIGNvbnN0IGRpc3RMb2dpY2FsSWQgPSBhd2FpdCBsb29rdXBEaXN0cmlidXRpb25Mb2dpY2FsSWRGcm9tQXJuKGRpc3QsIGV2ZW50LlN0YWNrSWQpO1xuICBpZiAoIWRpc3RMb2dpY2FsSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuYWJsZSB0byBsb2NhdGUgZGlzdHJpYnV0aW9uIGluIHN0YWNrJyk7XG4gIH1cblxuICAvLyBOT1RFOiBUaGlzIGxvZ2ljIG11c3QgYmUgZHVwbGljYXRlZCBleGFjdGx5IGZyb20gY29tcHV0ZVNhZmV0eUNoZWNrVGFnTmFtZVxuICBjb25zdCBzYWZldHlDaGVja1RleHQgPSBwcm9jZXNzLmVudi5DREtfU1RBQ0tfTkFNRSArICd8JyArIGRpc3RMb2dpY2FsSWQ7XG4gIGNvbnN0IHNhZmV0eUNoZWNrSGFzaCA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShzYWZldHlDaGVja1RleHQpLmRpZ2VzdCgnaGV4Jykuc2xpY2UoLTMyKTtcbiAgY29uc3QgdGFnTmFtZVJPID0gYGF3cy1jZGs6Z3JhbnQtZGlzdHJpYnV0aW9uLXJvOiR7c2FmZXR5Q2hlY2tIYXNofWA7XG4gIGNvbnN0IHRhZ05hbWVSVyA9IGBhd3MtY2RrOmdyYW50LWRpc3RyaWJ1dGlvbi1ydzoke3NhZmV0eUNoZWNrSGFzaH1gO1xuXG4gIGNvbnN0IGRlZHVwZVNldCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBoYXNOZXZlclNlZW4gPSAoZTogc3RyaW5nKSA9PiAhZGVkdXBlU2V0LmhhcyhlKSAmJiAhIWRlZHVwZVNldC5hZGQoZSk7XG4gIC8vIFByb2Nlc3MgYXJuc1JXIGZpcnN0IGluIGNhc2UgYW4gQVJOIGFwcGVhcnMgaW4gYm90aCBhcm5zUlcgYW5kIGFybnNST1xuICBjb25zdCBkZWR1cGVkUlcgPSBhcm5zUlcuZmlsdGVyKGhhc05ldmVyU2Vlbik7XG4gIGNvbnN0IGRlZHVwZWRSTyA9IGFybnNSTy5maWx0ZXIoaGFzTmV2ZXJTZWVuKTtcblxuICBjb25zdCBwb2xpY3lTaWQgPSBnZW5lcmF0ZVBvbGljeVNpZChwaHlzaWNhbElkKTtcbiAgY29uc3QgZGVsZXRlT25seSA9IGV2ZW50LlJlcXVlc3RUeXBlID09PSAnRGVsZXRlJztcbiAgYXdhaXQgcHJvY2Vzc0FybnMocG9saWN5U2lkLCBkaXN0LCBkZWR1cGVkUk8sIGRlZHVwZWRSVywgZGVsZXRlT25seSwgdGFnTmFtZVJPLCB0YWdOYW1lUlcpO1xuXG4gIHJldHVybiB7XG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbElkLFxuICB9O1xufVxuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/cdk.out b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/integ.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/integ.json new file mode 100644 index 0000000000000..313b647214f2b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "31.0.0", + "testCases": { + "CloudFrontS3OriginOACTest/DefaultTest": { + "stacks": [ + "oacmulti1", + "oacmulti2" + ], + "assertionStack": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert", + "assertionStackName": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/manifest.json new file mode 100644 index 0000000000000..e0d7cee209423 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/manifest.json @@ -0,0 +1,255 @@ +{ + "version": "31.0.0", + "artifacts": { + "oacmulti1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "oacmulti1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "oacmulti1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "oacmulti1.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}/9b0935451dfa260f24c316b45ad524218f432cb00a953b6c28f19bbf679c1cd6.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "oacmulti1.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": [ + "oacmulti1.assets" + ], + "metadata": { + "/oacmulti1/Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Bucket83908E77" + } + ], + "/oacmulti1/Bucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketPolicyE9A3008A" + } + ], + "/oacmulti1/BucketKMS/Key/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketKMSKeyCAB5A69D" + } + ], + "/oacmulti1/BucketKMS/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketKMS6F50E1CE" + } + ], + "/oacmulti1/BucketKMS/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketKMSPolicy86072B94" + } + ], + "/oacmulti1/PolicySetterRoleD30B3451CF91158A7CD35B67599D566D/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77" + } + ], + "/oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttBucket83908E77Arn063C8555" + } + ], + "/oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"Arn\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttBucketKMS6F50E1CEArn46806169" + } + ], + "/oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"BucketKMSKeyCAB5A69D\",\"Arn\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttBucketKMSKeyCAB5A69DArnBE1B734F" + } + ], + "/oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + } + ], + "/oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"RegionalDomainName\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttBucketKMS6F50E1CERegionalDomainName2B5BDDE9" + } + ], + "/oacmulti1/Exports/Output{\"Ref\":\"Bucket83908E77\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefBucket83908E7781C90AC0" + } + ], + "/oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77\",\"Arn\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttPolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77ArnFB08605E" + } + ], + "/oacmulti1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/oacmulti1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "oacmulti1" + }, + "oacmulti2.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "oacmulti2.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "oacmulti2": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "oacmulti2.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}/e0ab323b2ca33e95b42708c8d70fa442b83613ea1b88eaa6039d27465e8140da.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "oacmulti2.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": [ + "oacmulti1", + "oacmulti2.assets" + ], + "metadata": { + "/oacmulti2/Dist/PolicySetter1/CustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "DistPolicySetter1CustomResourceD490063B" + } + ], + "/oacmulti2/Dist/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DistB3B78991" + } + ], + "/oacmulti2/PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProviderHandlerD9E2933D" + } + ], + "/oacmulti2/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + ], + "/oacmulti2/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/oacmulti2/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "oacmulti2" + }, + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.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": [ + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.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": [ + "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets" + ], + "metadata": { + "/CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.assets.json similarity index 65% rename from packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json rename to packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.assets.json index f9b1e6ceebe60..bcb567b1eaba8 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.assets.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.assets.json @@ -1,15 +1,15 @@ { "version": "31.0.0", "files": { - "a67e710f43b68ae6f010f859dec3c563f3637bb9ea3a9ffc40af3a93c5ab360e": { + "9b0935451dfa260f24c316b45ad524218f432cb00a953b6c28f19bbf679c1cd6": { "source": { - "path": "s3origin-oac-multistack.template.json", + "path": "oacmulti1.template.json", "packaging": "file" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "a67e710f43b68ae6f010f859dec3c563f3637bb9ea3a9ffc40af3a93c5ab360e.json", + "objectKey": "9b0935451dfa260f24c316b45ad524218f432cb00a953b6c28f19bbf679c1cd6.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.template.json new file mode 100644 index 0000000000000..41f246d41443d --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti1.template.json @@ -0,0 +1,350 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:grant-distribution-ro:a6c9e748e49bfc560bd68feb959d634f", + "Value": "1" + }, + { + "Key": "aws-cdk:allow-policy-setter:d30b3451cf91158a7cd35b67599d566d", + "Value": "1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketPolicyE9A3008A": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "Bucket83908E77" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucketPolicy", + "s3:GetBucketTagging", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77", + "Arn" + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "BucketKMSKeyCAB5A69D": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:GetKeyPolicy", + "kms:ListResourceTags", + "kms:PutKeyPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "Description": "Created by oacmulti1/BucketKMS", + "Tags": [ + { + "Key": "aws-cdk:grant-distribution-rw:a6c9e748e49bfc560bd68feb959d634f", + "Value": "1" + }, + { + "Key": "aws-cdk:allow-policy-setter:d30b3451cf91158a7cd35b67599d566d", + "Value": "1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketKMS6F50E1CE": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { + "Fn::GetAtt": [ + "BucketKMSKeyCAB5A69D", + "Arn" + ] + }, + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "Tags": [ + { + "Key": "aws-cdk:grant-distribution-rw:a6c9e748e49bfc560bd68feb959d634f", + "Value": "1" + }, + { + "Key": "aws-cdk:allow-policy-setter:d30b3451cf91158a7cd35b67599d566d", + "Value": "1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketKMSPolicy86072B94": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "BucketKMS6F50E1CE" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucketPolicy", + "s3:GetBucketTagging", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77", + "Arn" + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "BucketKMS6F50E1CE", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "kms:GetKeyPolicy", + "kms:PutKeyPolicy", + "kms:ListResourceTags", + "s3:GetBucketPolicy", + "s3:PutBucketPolicy", + "s3:GetBucketTagging" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/aws-cdk:allow-policy-setter:d30b3451cf91158a7cd35b67599d566d": "1" + } + } + }, + { + "Effect": "Allow", + "Action": "cloudformation:DescribeStackResources", + "Resource": "*" + } + ] + } + } + ] + } + } + }, + "Outputs": { + "ExportsOutputFnGetAttBucket83908E77Arn063C8555": { + "Value": { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "Export": { + "Name": "oacmulti1:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + } + }, + "ExportsOutputFnGetAttBucketKMS6F50E1CEArn46806169": { + "Value": { + "Fn::GetAtt": [ + "BucketKMS6F50E1CE", + "Arn" + ] + }, + "Export": { + "Name": "oacmulti1:ExportsOutputFnGetAttBucketKMS6F50E1CEArn46806169" + } + }, + "ExportsOutputFnGetAttBucketKMSKeyCAB5A69DArnBE1B734F": { + "Value": { + "Fn::GetAtt": [ + "BucketKMSKeyCAB5A69D", + "Arn" + ] + }, + "Export": { + "Name": "oacmulti1:ExportsOutputFnGetAttBucketKMSKeyCAB5A69DArnBE1B734F" + } + }, + "ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631": { + "Value": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Export": { + "Name": "oacmulti1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + } + }, + "ExportsOutputFnGetAttBucketKMS6F50E1CERegionalDomainName2B5BDDE9": { + "Value": { + "Fn::GetAtt": [ + "BucketKMS6F50E1CE", + "RegionalDomainName" + ] + }, + "Export": { + "Name": "oacmulti1:ExportsOutputFnGetAttBucketKMS6F50E1CERegionalDomainName2B5BDDE9" + } + }, + "ExportsOutputRefBucket83908E7781C90AC0": { + "Value": { + "Ref": "Bucket83908E77" + }, + "Export": { + "Name": "oacmulti1:ExportsOutputRefBucket83908E7781C90AC0" + } + }, + "ExportsOutputFnGetAttPolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77ArnFB08605E": { + "Value": { + "Fn::GetAtt": [ + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77", + "Arn" + ] + }, + "Export": { + "Name": "oacmulti1:ExportsOutputFnGetAttPolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77ArnFB08605E" + } + } + }, + "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-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.assets.json similarity index 63% rename from packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json rename to packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.assets.json index 5ff5d77942e67..430be63f5490f 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.assets.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.assets.json @@ -1,28 +1,28 @@ { "version": "31.0.0", "files": { - "40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9": { + "4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b": { "source": { - "path": "asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9", + "path": "asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9.zip", + "objectKey": "4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "975ebefe3e22c5aaee8a2186d6e669e28c4bfc37ea1a312bf0d1041fbcd1de51": { + "e0ab323b2ca33e95b42708c8d70fa442b83613ea1b88eaa6039d27465e8140da": { "source": { - "path": "s3origin-oac-1.template.json", + "path": "oacmulti2.template.json", "packaging": "file" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "975ebefe3e22c5aaee8a2186d6e669e28c4bfc37ea1a312bf0d1041fbcd1de51.json", + "objectKey": "e0ab323b2ca33e95b42708c8d70fa442b83613ea1b88eaa6039d27465e8140da.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.template.json new file mode 100644 index 0000000000000..664cfc9fb0114 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/oacmulti2.template.json @@ -0,0 +1,226 @@ +{ + "Resources": { + "DistPolicySetter1CustomResourceD490063B": { + "Type": "Custom::CDKCloudFrontDistributionPolicySetter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProviderHandlerD9E2933D", + "Arn" + ] + }, + "distribution": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistB3B78991" + } + ] + ] + }, + "readOnlyArns": [ + { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + } + ], + "readWriteArns": [ + { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttBucketKMS6F50E1CEArn46806169" + }, + { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttBucketKMSKeyCAB5A69DArnBE1B734F" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "DistB3B78991": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "CacheBehaviors": [ + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "0/*", + "TargetOriginId": "oacmulti2DistOrigin2D8BB3040", + "ViewerProtocolPolicy": "allow-all" + }, + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "1/*", + "TargetOriginId": "oacmulti2DistOrigin30A5968F5", + "ViewerProtocolPolicy": "allow-all" + }, + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "2/*", + "TargetOriginId": "oacmulti2DistOrigin4EBCB1182", + "ViewerProtocolPolicy": "allow-all" + } + ], + "DefaultCacheBehavior": { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "TargetOriginId": "oacmulti2DistOrigin12E55B092", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "DomainName": { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + }, + "Id": "oacmulti2DistOrigin12E55B092", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttBucketKMS6F50E1CERegionalDomainName2B5BDDE9" + }, + "Id": "oacmulti2DistOrigin2D8BB3040", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "oacmulti1:ExportsOutputRefBucket83908E7781C90AC0" + }, + ".s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "Id": "oacmulti2DistOrigin30A5968F5", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + }, + { + "DomainName": { + "Fn::Join": [ + "", + [ + "s3origin-oac-test-bucket.s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "Id": "oacmulti2DistOrigin4EBCB1182", + "OriginAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + }, + "S3OriginConfig": {} + } + ] + } + } + }, + "PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProviderHandlerD9E2933D": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttPolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77ArnFB08605E" + }, + "Runtime": "nodejs16.x", + "Environment": { + "Variables": { + "AWS_STS_REGIONAL_ENDPOINTS": "regional", + "CDK_STACK_NAME": "oacmulti2" + } + } + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28": { + "Type": "AWS::CloudFront::OriginAccessControl", + "Properties": { + "OriginAccessControlConfig": { + "Name": "oacmulti2OriginAccessControlEFE0CA7DB170D0C7D8E8DC4943CF6C44F77B", + "OriginAccessControlOriginType": "s3", + "SigningBehavior": "always", + "SigningProtocol": "sigv4" + } + } + } + }, + "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-origins/test/integ.s3-origin-oac-multistack.js.snapshot/tree.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/tree.json new file mode 100644 index 0000000000000..ecdbdbe92a021 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.js.snapshot/tree.json @@ -0,0 +1,735 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "oacmulti1": { + "id": "oacmulti1", + "path": "oacmulti1", + "children": { + "Bucket": { + "id": "Bucket", + "path": "oacmulti1/Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "oacmulti1/Bucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "aws-cdk:grant-distribution-ro:a6c9e748e49bfc560bd68feb959d634f", + "value": "1" + }, + { + "key": "aws-cdk:allow-policy-setter:d30b3451cf91158a7cd35b67599d566d", + "value": "1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "oacmulti1/Bucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "oacmulti1/Bucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "Bucket83908E77" + }, + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucketPolicy", + "s3:GetBucketTagging", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77", + "Arn" + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "BucketHardcoded": { + "id": "BucketHardcoded", + "path": "oacmulti1/BucketHardcoded", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + }, + "BucketImported": { + "id": "BucketImported", + "path": "oacmulti1/BucketImported", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + }, + "BucketKMS": { + "id": "BucketKMS", + "path": "oacmulti1/BucketKMS", + "children": { + "Key": { + "id": "Key", + "path": "oacmulti1/BucketKMS/Key", + "children": { + "Resource": { + "id": "Resource", + "path": "oacmulti1/BucketKMS/Key/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:GetKeyPolicy", + "kms:ListResourceTags", + "kms:PutKeyPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "description": "Created by oacmulti1/BucketKMS", + "tags": [ + { + "key": "aws-cdk:grant-distribution-rw:a6c9e748e49bfc560bd68feb959d634f", + "value": "1" + }, + { + "key": "aws-cdk:allow-policy-setter:d30b3451cf91158a7cd35b67599d566d", + "value": "1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.CfnKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.Key", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "oacmulti1/BucketKMS/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "aws:kms", + "kmsMasterKeyId": { + "Fn::GetAtt": [ + "BucketKMSKeyCAB5A69D", + "Arn" + ] + } + } + } + ] + }, + "tags": [ + { + "key": "aws-cdk:grant-distribution-rw:a6c9e748e49bfc560bd68feb959d634f", + "value": "1" + }, + { + "key": "aws-cdk:allow-policy-setter:d30b3451cf91158a7cd35b67599d566d", + "value": "1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "oacmulti1/BucketKMS/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "oacmulti1/BucketKMS/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "BucketKMS6F50E1CE" + }, + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucketPolicy", + "s3:GetBucketTagging", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77", + "Arn" + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "BucketKMS6F50E1CE", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "PolicySetterRoleD30B3451CF91158A7CD35B67599D566D": { + "id": "PolicySetterRoleD30B3451CF91158A7CD35B67599D566D", + "path": "oacmulti1/PolicySetterRoleD30B3451CF91158A7CD35B67599D566D", + "children": { + "Role": { + "id": "Role", + "path": "oacmulti1/PolicySetterRoleD30B3451CF91158A7CD35B67599D566D/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Exports": { + "id": "Exports", + "path": "oacmulti1/Exports", + "children": { + "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}", + "path": "oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"Arn\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"Arn\"]}", + "path": "oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"Arn\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Fn::GetAtt\":[\"BucketKMSKeyCAB5A69D\",\"Arn\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"BucketKMSKeyCAB5A69D\",\"Arn\"]}", + "path": "oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"BucketKMSKeyCAB5A69D\",\"Arn\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}", + "path": "oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"RegionalDomainName\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"RegionalDomainName\"]}", + "path": "oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"BucketKMS6F50E1CE\",\"RegionalDomainName\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Ref\":\"Bucket83908E77\"}": { + "id": "Output{\"Ref\":\"Bucket83908E77\"}", + "path": "oacmulti1/Exports/Output{\"Ref\":\"Bucket83908E77\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Fn::GetAtt\":[\"PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77\",\"Arn\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77\",\"Arn\"]}", + "path": "oacmulti1/Exports/Output{\"Fn::GetAtt\":[\"PolicySetterRoleD30B3451CF91158A7CD35B67599D566DRole66B1FE77\",\"Arn\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "oacmulti1/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "oacmulti1/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "oacmulti2": { + "id": "oacmulti2", + "path": "oacmulti2", + "children": { + "Dist": { + "id": "Dist", + "path": "oacmulti2/Dist", + "children": { + "Origin1": { + "id": "Origin1", + "path": "oacmulti2/Dist/Origin1", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "PolicySetter1": { + "id": "PolicySetter1", + "path": "oacmulti2/Dist/PolicySetter1", + "children": { + "CustomResource": { + "id": "CustomResource", + "path": "oacmulti2/Dist/PolicySetter1/CustomResource", + "children": { + "Default": { + "id": "Default", + "path": "oacmulti2/Dist/PolicySetter1/CustomResource/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "oacmulti2/Dist/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", + "aws:cdk:cloudformation:props": { + "distributionConfig": { + "enabled": true, + "origins": [ + { + "domainName": { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + }, + "id": "oacmulti2DistOrigin12E55B092", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::ImportValue": "oacmulti1:ExportsOutputFnGetAttBucketKMS6F50E1CERegionalDomainName2B5BDDE9" + }, + "id": "oacmulti2DistOrigin2D8BB3040", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "oacmulti1:ExportsOutputRefBucket83908E7781C90AC0" + }, + ".s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "id": "oacmulti2DistOrigin30A5968F5", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + }, + { + "domainName": { + "Fn::Join": [ + "", + [ + "s3origin-oac-test-bucket.s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "id": "oacmulti2DistOrigin4EBCB1182", + "s3OriginConfig": {}, + "originAccessControlId": { + "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + } + } + ], + "defaultCacheBehavior": { + "pathPattern": "*", + "targetOriginId": "oacmulti2DistOrigin12E55B092", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + "cacheBehaviors": [ + { + "pathPattern": "0/*", + "targetOriginId": "oacmulti2DistOrigin2D8BB3040", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + { + "pathPattern": "1/*", + "targetOriginId": "oacmulti2DistOrigin30A5968F5", + "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "compress": true, + "viewerProtocolPolicy": "allow-all" + }, + { + "pathPattern": "2/*", + "targetOriginId": "oacmulti2DistOrigin4EBCB1182", + "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" + } + }, + "Origin2": { + "id": "Origin2", + "path": "oacmulti2/Dist/Origin2", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Origin3": { + "id": "Origin3", + "path": "oacmulti2/Dist/Origin3", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Origin4": { + "id": "Origin4", + "path": "oacmulti2/Dist/Origin4", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.Distribution", + "version": "0.0.0" + } + }, + "PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProvider": { + "id": "PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProvider", + "path": "oacmulti2/PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "oacmulti2/PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "oacmulti2/PolicySetterProviderD30B3451CF91158A7CD35B67599D566DCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResourceProvider", + "version": "0.0.0" + } + }, + "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF": { + "id": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "path": "oacmulti2/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "children": { + "Resource": { + "id": "Resource", + "path": "oacmulti2/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", + "aws:cdk:cloudformation:props": { + "originAccessControlConfig": { + "name": "oacmulti2OriginAccessControlEFE0CA7DB170D0C7D8E8DC4943CF6C44F77B", + "originAccessControlOriginType": "s3", + "signingBehavior": "always", + "signingProtocol": "sigv4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudfront.OriginAccessControl", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "oacmulti2/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "oacmulti2/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "CloudFrontS3OriginOACTest": { + "id": "CloudFrontS3OriginOACTest", + "path": "CloudFrontS3OriginOACTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "CloudFrontS3OriginOACTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "CloudFrontS3OriginOACTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "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" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.ts new file mode 100644 index 0000000000000..8e7b18beb0b81 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac-multistack.ts @@ -0,0 +1,50 @@ +import * as cloudfront from '@aws-cdk/aws-cloudfront'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import * as origins from '../lib'; + +class TestS3OriginOAC extends origins.S3Origin { + constructor( + bucket: s3.IBucket, + policy?: origins.S3OriginAutoResourcePolicy | boolean, + oac?: cloudfront.OriginAccessControl, + ) { + super(bucket, { + autoResourcePolicy: policy, + originAccessControl: oac ?? true, + }); + } +} + +function makeDistribution(stack: cdk.Stack, id: string, first: cloudfront.IOrigin, ...more: cloudfront.IOrigin[]) { + const dist = new cloudfront.Distribution(stack, id, { + defaultBehavior: { origin: first }, + }); + more.forEach((o, idx) => dist.addBehavior(`${idx}/*`, o)); +} + +const app = new cdk.App(); + +const stack1 = new cdk.Stack(app, 'oacmulti1'); +const bucket = new s3.Bucket(stack1, 'Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY }); +const bucketByName = s3.Bucket.fromBucketName(stack1, 'BucketHardcoded', 's3origin-oac-test-bucket'); +const bucketImport = s3.Bucket.fromBucketName(stack1, 'BucketImported', bucket.bucketName); + +const bucketWithKMS = new s3.Bucket(stack1, 'BucketKMS', { + encryption: s3.BucketEncryption.KMS, + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); +bucketWithKMS.encryptionKey?.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY); + +const stack2 = new cdk.Stack(app, 'oacmulti2'); +makeDistribution(stack2, 'Dist', + new TestS3OriginOAC(bucket), + new TestS3OriginOAC(bucketWithKMS, origins.S3OriginAutoResourcePolicy.READ_WRITE), + new TestS3OriginOAC(bucketImport, false), + new TestS3OriginOAC(bucketByName, false), +); + +new integ.IntegTest(app, 'CloudFrontS3OriginOACTest', { + testCases: [stack1, stack2], +}); diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js deleted file mode 100644 index bf260b9069cd1..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9/index.js +++ /dev/null @@ -1,78 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.handler = void 0; -// eslint-disable-next-line import/no-extraneous-dependencies -const aws_sdk_1 = require("aws-sdk"); -const AUTO_DELETE_OBJECTS_TAG = 'aws-cdk:auto-delete-objects'; -const s3 = new aws_sdk_1.S3(); -async function handler(event) { - switch (event.RequestType) { - case 'Create': - return; - case 'Update': - return onUpdate(event); - case 'Delete': - return onDelete(event.ResourceProperties?.BucketName); - } -} -exports.handler = handler; -async function onUpdate(event) { - const updateEvent = event; - const oldBucketName = updateEvent.OldResourceProperties?.BucketName; - const newBucketName = updateEvent.ResourceProperties?.BucketName; - const bucketNameHasChanged = newBucketName != null && oldBucketName != null && newBucketName !== oldBucketName; - /* If the name of the bucket has changed, CloudFormation will try to delete the bucket - and create a new one with the new name. So we have to delete the contents of the - bucket so that this operation does not fail. */ - if (bucketNameHasChanged) { - return onDelete(oldBucketName); - } -} -/** - * Recursively delete all items in the bucket - * - * @param bucketName the bucket name - */ -async function emptyBucket(bucketName) { - const listedObjects = await s3.listObjectVersions({ Bucket: bucketName }).promise(); - const contents = [...listedObjects.Versions ?? [], ...listedObjects.DeleteMarkers ?? []]; - if (contents.length === 0) { - return; - } - const records = contents.map((record) => ({ Key: record.Key, VersionId: record.VersionId })); - await s3.deleteObjects({ Bucket: bucketName, Delete: { Objects: records } }).promise(); - if (listedObjects?.IsTruncated) { - await emptyBucket(bucketName); - } -} -async function onDelete(bucketName) { - if (!bucketName) { - throw new Error('No BucketName was provided.'); - } - if (!await isBucketTaggedForDeletion(bucketName)) { - process.stdout.write(`Bucket does not have '${AUTO_DELETE_OBJECTS_TAG}' tag, skipping cleaning.\n`); - return; - } - try { - await emptyBucket(bucketName); - } - catch (e) { - if (e.code !== 'NoSuchBucket') { - throw e; - } - // Bucket doesn't exist. Ignoring - } -} -/** - * The bucket will only be tagged for deletion if it's being deleted in the same - * deployment as this Custom Resource. - * - * If the Custom Resource is every deleted before the bucket, it must be because - * `autoDeleteObjects` has been switched to false, in which case the tag would have - * been removed before we get to this Delete event. - */ -async function isBucketTaggedForDeletion(bucketName) { - const response = await s3.getBucketTagging({ Bucket: bucketName }).promise(); - return response.TagSet.some(tag => tag.Key === AUTO_DELETE_OBJECTS_TAG && tag.Value === 'true'); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBNkQ7QUFDN0QscUNBQTZCO0FBRTdCLE1BQU0sdUJBQXVCLEdBQUcsNkJBQTZCLENBQUM7QUFFOUQsTUFBTSxFQUFFLEdBQUcsSUFBSSxZQUFFLEVBQUUsQ0FBQztBQUViLEtBQUssVUFBVSxPQUFPLENBQUMsS0FBa0Q7SUFDOUUsUUFBUSxLQUFLLENBQUMsV0FBVyxFQUFFO1FBQ3pCLEtBQUssUUFBUTtZQUNYLE9BQU87UUFDVCxLQUFLLFFBQVE7WUFDWCxPQUFPLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6QixLQUFLLFFBQVE7WUFDWCxPQUFPLFFBQVEsQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsVUFBVSxDQUFDLENBQUM7S0FDekQ7QUFDSCxDQUFDO0FBVEQsMEJBU0M7QUFFRCxLQUFLLFVBQVUsUUFBUSxDQUFDLEtBQWtEO0lBQ3hFLE1BQU0sV0FBVyxHQUFHLEtBQTBELENBQUM7SUFDL0UsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFDLHFCQUFxQixFQUFFLFVBQVUsQ0FBQztJQUNwRSxNQUFNLGFBQWEsR0FBRyxXQUFXLENBQUMsa0JBQWtCLEVBQUUsVUFBVSxDQUFDO0lBQ2pFLE1BQU0sb0JBQW9CLEdBQUcsYUFBYSxJQUFJLElBQUksSUFBSSxhQUFhLElBQUksSUFBSSxJQUFJLGFBQWEsS0FBSyxhQUFhLENBQUM7SUFFL0c7O3NEQUVrRDtJQUNsRCxJQUFJLG9CQUFvQixFQUFFO1FBQ3hCLE9BQU8sUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0tBQ2hDO0FBQ0gsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxLQUFLLFVBQVUsV0FBVyxDQUFDLFVBQWtCO0lBQzNDLE1BQU0sYUFBYSxHQUFHLE1BQU0sRUFBRSxDQUFDLGtCQUFrQixDQUFDLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDcEYsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxRQUFRLElBQUksRUFBRSxFQUFFLEdBQUcsYUFBYSxDQUFDLGFBQWEsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN6RixJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQ3pCLE9BQU87S0FDUjtJQUVELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFXLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUcsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNsRyxNQUFNLEVBQUUsQ0FBQyxhQUFhLENBQUMsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFFdkYsSUFBSSxhQUFhLEVBQUUsV0FBVyxFQUFFO1FBQzlCLE1BQU0sV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0tBQy9CO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxRQUFRLENBQUMsVUFBbUI7SUFDekMsSUFBSSxDQUFDLFVBQVUsRUFBRTtRQUNmLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztLQUNoRDtJQUNELElBQUksQ0FBQyxNQUFNLHlCQUF5QixDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQ2hELE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5Qix1QkFBdUIsNkJBQTZCLENBQUMsQ0FBQztRQUNwRyxPQUFPO0tBQ1I7SUFDRCxJQUFJO1FBQ0YsTUFBTSxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7S0FDL0I7SUFBQyxPQUFPLENBQU0sRUFBRTtRQUNmLElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxjQUFjLEVBQUU7WUFDN0IsTUFBTSxDQUFDLENBQUM7U0FDVDtRQUNELGlDQUFpQztLQUNsQztBQUNILENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsS0FBSyxVQUFVLHlCQUF5QixDQUFDLFVBQWtCO0lBQ3pELE1BQU0sUUFBUSxHQUFHLE1BQU0sRUFBRSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDN0UsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssdUJBQXVCLElBQUksR0FBRyxDQUFDLEtBQUssS0FBSyxNQUFNLENBQUMsQ0FBQztBQUNsRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHsgUzMgfSBmcm9tICdhd3Mtc2RrJztcblxuY29uc3QgQVVUT19ERUxFVEVfT0JKRUNUU19UQUcgPSAnYXdzLWNkazphdXRvLWRlbGV0ZS1vYmplY3RzJztcblxuY29uc3QgczMgPSBuZXcgUzMoKTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQpIHtcbiAgc3dpdGNoIChldmVudC5SZXF1ZXN0VHlwZSkge1xuICAgIGNhc2UgJ0NyZWF0ZSc6XG4gICAgICByZXR1cm47XG4gICAgY2FzZSAnVXBkYXRlJzpcbiAgICAgIHJldHVybiBvblVwZGF0ZShldmVudCk7XG4gICAgY2FzZSAnRGVsZXRlJzpcbiAgICAgIHJldHVybiBvbkRlbGV0ZShldmVudC5SZXNvdXJjZVByb3BlcnRpZXM/LkJ1Y2tldE5hbWUpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG9uVXBkYXRlKGV2ZW50OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50KSB7XG4gIGNvbnN0IHVwZGF0ZUV2ZW50ID0gZXZlbnQgYXMgQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VVcGRhdGVFdmVudDtcbiAgY29uc3Qgb2xkQnVja2V0TmFtZSA9IHVwZGF0ZUV2ZW50Lk9sZFJlc291cmNlUHJvcGVydGllcz8uQnVja2V0TmFtZTtcbiAgY29uc3QgbmV3QnVja2V0TmFtZSA9IHVwZGF0ZUV2ZW50LlJlc291cmNlUHJvcGVydGllcz8uQnVja2V0TmFtZTtcbiAgY29uc3QgYnVja2V0TmFtZUhhc0NoYW5nZWQgPSBuZXdCdWNrZXROYW1lICE9IG51bGwgJiYgb2xkQnVja2V0TmFtZSAhPSBudWxsICYmIG5ld0J1Y2tldE5hbWUgIT09IG9sZEJ1Y2tldE5hbWU7XG5cbiAgLyogSWYgdGhlIG5hbWUgb2YgdGhlIGJ1Y2tldCBoYXMgY2hhbmdlZCwgQ2xvdWRGb3JtYXRpb24gd2lsbCB0cnkgdG8gZGVsZXRlIHRoZSBidWNrZXRcbiAgICAgYW5kIGNyZWF0ZSBhIG5ldyBvbmUgd2l0aCB0aGUgbmV3IG5hbWUuIFNvIHdlIGhhdmUgdG8gZGVsZXRlIHRoZSBjb250ZW50cyBvZiB0aGVcbiAgICAgYnVja2V0IHNvIHRoYXQgdGhpcyBvcGVyYXRpb24gZG9lcyBub3QgZmFpbC4gKi9cbiAgaWYgKGJ1Y2tldE5hbWVIYXNDaGFuZ2VkKSB7XG4gICAgcmV0dXJuIG9uRGVsZXRlKG9sZEJ1Y2tldE5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgZGVsZXRlIGFsbCBpdGVtcyBpbiB0aGUgYnVja2V0XG4gKlxuICogQHBhcmFtIGJ1Y2tldE5hbWUgdGhlIGJ1Y2tldCBuYW1lXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGVtcHR5QnVja2V0KGJ1Y2tldE5hbWU6IHN0cmluZykge1xuICBjb25zdCBsaXN0ZWRPYmplY3RzID0gYXdhaXQgczMubGlzdE9iamVjdFZlcnNpb25zKHsgQnVja2V0OiBidWNrZXROYW1lIH0pLnByb21pc2UoKTtcbiAgY29uc3QgY29udGVudHMgPSBbLi4ubGlzdGVkT2JqZWN0cy5WZXJzaW9ucyA/PyBbXSwgLi4ubGlzdGVkT2JqZWN0cy5EZWxldGVNYXJrZXJzID8/IFtdXTtcbiAgaWYgKGNvbnRlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHJlY29yZHMgPSBjb250ZW50cy5tYXAoKHJlY29yZDogYW55KSA9PiAoeyBLZXk6IHJlY29yZC5LZXksIFZlcnNpb25JZDogcmVjb3JkLlZlcnNpb25JZCB9KSk7XG4gIGF3YWl0IHMzLmRlbGV0ZU9iamVjdHMoeyBCdWNrZXQ6IGJ1Y2tldE5hbWUsIERlbGV0ZTogeyBPYmplY3RzOiByZWNvcmRzIH0gfSkucHJvbWlzZSgpO1xuXG4gIGlmIChsaXN0ZWRPYmplY3RzPy5Jc1RydW5jYXRlZCkge1xuICAgIGF3YWl0IGVtcHR5QnVja2V0KGJ1Y2tldE5hbWUpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG9uRGVsZXRlKGJ1Y2tldE5hbWU/OiBzdHJpbmcpIHtcbiAgaWYgKCFidWNrZXROYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBCdWNrZXROYW1lIHdhcyBwcm92aWRlZC4nKTtcbiAgfVxuICBpZiAoIWF3YWl0IGlzQnVja2V0VGFnZ2VkRm9yRGVsZXRpb24oYnVja2V0TmFtZSkpIHtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShgQnVja2V0IGRvZXMgbm90IGhhdmUgJyR7QVVUT19ERUxFVEVfT0JKRUNUU19UQUd9JyB0YWcsIHNraXBwaW5nIGNsZWFuaW5nLlxcbmApO1xuICAgIHJldHVybjtcbiAgfVxuICB0cnkge1xuICAgIGF3YWl0IGVtcHR5QnVja2V0KGJ1Y2tldE5hbWUpO1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBpZiAoZS5jb2RlICE9PSAnTm9TdWNoQnVja2V0Jykge1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gICAgLy8gQnVja2V0IGRvZXNuJ3QgZXhpc3QuIElnbm9yaW5nXG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgYnVja2V0IHdpbGwgb25seSBiZSB0YWdnZWQgZm9yIGRlbGV0aW9uIGlmIGl0J3MgYmVpbmcgZGVsZXRlZCBpbiB0aGUgc2FtZVxuICogZGVwbG95bWVudCBhcyB0aGlzIEN1c3RvbSBSZXNvdXJjZS5cbiAqXG4gKiBJZiB0aGUgQ3VzdG9tIFJlc291cmNlIGlzIGV2ZXJ5IGRlbGV0ZWQgYmVmb3JlIHRoZSBidWNrZXQsIGl0IG11c3QgYmUgYmVjYXVzZVxuICogYGF1dG9EZWxldGVPYmplY3RzYCBoYXMgYmVlbiBzd2l0Y2hlZCB0byBmYWxzZSwgaW4gd2hpY2ggY2FzZSB0aGUgdGFnIHdvdWxkIGhhdmVcbiAqIGJlZW4gcmVtb3ZlZCBiZWZvcmUgd2UgZ2V0IHRvIHRoaXMgRGVsZXRlIGV2ZW50LlxuICovXG5hc3luYyBmdW5jdGlvbiBpc0J1Y2tldFRhZ2dlZEZvckRlbGV0aW9uKGJ1Y2tldE5hbWU6IHN0cmluZykge1xuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHMzLmdldEJ1Y2tldFRhZ2dpbmcoeyBCdWNrZXQ6IGJ1Y2tldE5hbWUgfSkucHJvbWlzZSgpO1xuICByZXR1cm4gcmVzcG9uc2UuVGFnU2V0LnNvbWUodGFnID0+IHRhZy5LZXkgPT09IEFVVE9fREVMRVRFX09CSkVDVFNfVEFHICYmIHRhZy5WYWx1ZSA9PT0gJ3RydWUnKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/__entrypoint__.js b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/__entrypoint__.js new file mode 100644 index 0000000000000..c83ecebaaadac --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/__entrypoint__.js @@ -0,0 +1,147 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withRetries = exports.handler = exports.external = void 0; +const https = require("https"); +const url = require("url"); +// for unit tests +exports.external = { + sendHttpRequest: defaultSendHttpRequest, + log: defaultLog, + includeStackTraces: true, + userHandlerIndex: './index', +}; +const CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; +const MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; +async function handler(event, context) { + const sanitizedEvent = { ...event, ResponseURL: '...' }; + exports.external.log(JSON.stringify(sanitizedEvent, undefined, 2)); + // ignore DELETE event when the physical resource ID is the marker that + // indicates that this DELETE is a subsequent DELETE to a failed CREATE + // operation. + if (event.RequestType === 'Delete' && event.PhysicalResourceId === CREATE_FAILED_PHYSICAL_ID_MARKER) { + exports.external.log('ignoring DELETE event caused by a failed CREATE event'); + await submitResponse('SUCCESS', event); + return; + } + try { + // invoke the user handler. this is intentionally inside the try-catch to + // ensure that if there is an error it's reported as a failure to + // cloudformation (otherwise cfn waits). + // eslint-disable-next-line @typescript-eslint/no-require-imports + const userHandler = require(exports.external.userHandlerIndex).handler; + const result = await userHandler(sanitizedEvent, context); + // validate user response and create the combined event + const responseEvent = renderResponse(event, result); + // submit to cfn as success + await submitResponse('SUCCESS', responseEvent); + } + catch (e) { + const resp = { + ...event, + Reason: exports.external.includeStackTraces ? e.stack : e.message, + }; + if (!resp.PhysicalResourceId) { + // special case: if CREATE fails, which usually implies, we usually don't + // have a physical resource id. in this case, the subsequent DELETE + // operation does not have any meaning, and will likely fail as well. to + // address this, we use a marker so the provider framework can simply + // ignore the subsequent DELETE. + if (event.RequestType === 'Create') { + exports.external.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); + resp.PhysicalResourceId = CREATE_FAILED_PHYSICAL_ID_MARKER; + } + else { + // otherwise, if PhysicalResourceId is not specified, something is + // terribly wrong because all other events should have an ID. + exports.external.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(event)}`); + } + } + // this is an actual error, fail the activity altogether and exist. + await submitResponse('FAILED', resp); + } +} +exports.handler = handler; +function renderResponse(cfnRequest, handlerResponse = {}) { + // if physical ID is not returned, we have some defaults for you based + // on the request type. + const physicalResourceId = handlerResponse.PhysicalResourceId ?? cfnRequest.PhysicalResourceId ?? cfnRequest.RequestId; + // if we are in DELETE and physical ID was changed, it's an error. + if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { + throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${handlerResponse.PhysicalResourceId}" during deletion`); + } + // merge request event and result event (result prevails). + return { + ...cfnRequest, + ...handlerResponse, + PhysicalResourceId: physicalResourceId, + }; +} +async function submitResponse(status, event) { + const json = { + Status: status, + Reason: event.Reason ?? status, + StackId: event.StackId, + RequestId: event.RequestId, + PhysicalResourceId: event.PhysicalResourceId || MISSING_PHYSICAL_ID_MARKER, + LogicalResourceId: event.LogicalResourceId, + NoEcho: event.NoEcho, + Data: event.Data, + }; + exports.external.log('submit response to cloudformation', json); + const responseBody = JSON.stringify(json); + const parsedUrl = url.parse(event.ResponseURL); + const req = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'content-type': '', + 'content-length': Buffer.byteLength(responseBody, 'utf8'), + }, + }; + const retryOptions = { + attempts: 5, + sleep: 1000, + }; + await withRetries(retryOptions, exports.external.sendHttpRequest)(req, responseBody); +} +async function defaultSendHttpRequest(options, responseBody) { + return new Promise((resolve, reject) => { + try { + const request = https.request(options, _ => resolve()); + request.on('error', reject); + request.write(responseBody); + request.end(); + } + catch (e) { + reject(e); + } + }); +} +function defaultLog(fmt, ...params) { + // eslint-disable-next-line no-console + console.log(fmt, ...params); +} +function withRetries(options, fn) { + return async (...xs) => { + let attempts = options.attempts; + let ms = options.sleep; + while (true) { + try { + return await fn(...xs); + } + catch (e) { + if (attempts-- <= 0) { + throw e; + } + await sleep(Math.floor(Math.random() * ms)); + ms *= 2; + } + } + }; +} +exports.withRetries = withRetries; +async function sleep(ms) { + return new Promise((ok) => setTimeout(ok, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWpzLWVudHJ5cG9pbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJub2RlanMtZW50cnlwb2ludC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBRTNCLGlCQUFpQjtBQUNKLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLGVBQWUsRUFBRSxzQkFBc0I7SUFDdkMsR0FBRyxFQUFFLFVBQVU7SUFDZixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGdCQUFnQixFQUFFLFNBQVM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sZ0NBQWdDLEdBQUcsd0RBQXdELENBQUM7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyw4REFBOEQsQ0FBQztBQVczRixLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQWtELEVBQUUsT0FBMEI7SUFDMUcsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDeEQsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFM0QsdUVBQXVFO0lBQ3ZFLHVFQUF1RTtJQUN2RSxhQUFhO0lBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssZ0NBQWdDLEVBQUU7UUFDbkcsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN0RSxNQUFNLGNBQWMsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsT0FBTztLQUNSO0lBRUQsSUFBSTtRQUNGLHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsd0NBQXdDO1FBQ3hDLGlFQUFpRTtRQUNqRSxNQUFNLFdBQVcsR0FBWSxPQUFPLENBQUMsZ0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxNQUFN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LE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBSyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxFQUFFO1lBQ1gsSUFBSTtnQkFDRixPQUFPLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDeEI7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDbkIsTUFBTSxDQUFDLENBQUM7aUJBQ1Q7Z0JBQ0QsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNUO1NBQ0Y7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDO0FBaEJELGtDQWdCQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM3QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG4vLyBmb3IgdW5pdCB0ZXN0c1xuZXhwb3J0IGNvbnN0IGV4dGVybmFsID0ge1xuICBzZW5kSHR0cFJlcXVlc3Q6IGRlZmF1bHRTZW5kSHR0cFJlcXVlc3QsXG4gIGxvZzogZGVmYXVsdExvZyxcbiAgaW5jbHVkZVN0YWNrVHJhY2VzOiB0cnVlLFxuICB1c2VySGFuZGxlckluZGV4OiAnLi9pbmRleCcsXG59O1xuXG5jb25zdCBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6OkNSRUFURV9GQUlMRUQnO1xuY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IHR5cGUgUmVzcG9uc2UgPSBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgSGFuZGxlclJlc3BvbnNlO1xuZXhwb3J0IHR5cGUgSGFuZGxlciA9IChldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpID0+IFByb21pc2U8SGFuZGxlclJlc3BvbnNlIHwgdm9pZD47XG5leHBvcnQgdHlwZSBIYW5kbGVyUmVzcG9uc2UgPSB1bmRlZmluZWQgfCB7XG4gIERhdGE/OiBhbnk7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBOb0VjaG8/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIGNvbnRleHQ6IEFXU0xhbWJkYS5Db250ZXh0KSB7XG4gIGNvbnN0IHNhbml0aXplZEV2ZW50ID0geyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH07XG4gIGV4dGVybmFsLmxvZyhKU09OLnN0cmluZ2lmeShzYW5pdGl6ZWRFdmVudCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgLy8gaWdub3JlIERFTEVURSBldmVudCB3aGVuIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBJRCBpcyB0aGUgbWFya2VyIHRoYXRcbiAgLy8gaW5kaWNhdGVzIHRoYXQgdGhpcyBERUxFVEUgaXMgYSBzdWJzZXF1ZW50IERFTEVURSB0byBhIGZhaWxlZCBDUkVBVEVcbiAgLy8gb3BlcmF0aW9uLlxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9PT0gQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIpIHtcbiAgICBleHRlcm5hbC5sb2coJ2lnbm9yaW5nIERFTEVURSBldmVudCBjYXVzZWQgYnkgYSBmYWlsZWQgQ1JFQVRFIGV2ZW50Jyk7XG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBpbnZva2UgdGhlIHVzZXIgaGFuZGxlci4gdGhpcyBpcyBpbnRlbnRpb25hbGx5IGluc2lkZSB0aGUgdHJ5LWNhdGNoIHRvXG4gICAgLy8gZW5zdXJlIHRoYXQgaWYgdGhlcmUgaXMgYW4gZXJyb3IgaXQncyByZXBvcnRlZCBhcyBhIGZhaWx1cmUgdG9cbiAgICAvLyBjbG91ZGZvcm1hdGlvbiAob3RoZXJ3aXNlIGNmbiB3YWl0cykuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB1c2VySGFuZGxlcjogSGFuZGxlciA9IHJlcXVpcmUoZXh0ZXJuYWwudXNlckhhbmRsZXJJbmRleCkuaGFuZGxlcjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB1c2VySGFuZGxlcihzYW5pdGl6ZWRFdmVudCwgY29udGV4dCk7XG5cbiAgICAvLyB2YWxpZGF0ZSB1c2VyIHJlc3BvbnNlIGFuZCBjcmVhdGUgdGhlIGNvbWJpbmVkIGV2ZW50XG4gICAgY29uc3QgcmVzcG9uc2VFdmVudCA9IHJlbmRlclJlc3BvbnNlKGV2ZW50LCByZXN1bHQpO1xuXG4gICAgLy8gc3VibWl0IHRvIGNmbiBhcyBzdWNjZXNzXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCByZXNwb25zZUV2ZW50KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc3QgcmVzcDogUmVzcG9uc2UgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlYXNvbjogZXh0ZXJuYWwuaW5jbHVkZVN0YWNrVHJhY2VzID8gZS5zdGFjayA6IGUubWVzc2FnZSxcbiAgICB9O1xuXG4gICAgaWYgKCFyZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCkge1xuICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgLy8gaGF2ZSBhIHBoeXNpY2FsIHJlc291cmNlIGlkLiBpbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXF1ZW50IERFTEVURVxuICAgICAgLy8gb3BlcmF0aW9uIGRvZXMgbm90IGhhdmUgYW55IG1lYW5pbmcsIGFuZCB3aWxsIGxpa2VseSBmYWlsIGFzIHdlbGwuIHRvXG4gICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgIC8vIGlnbm9yZSB0aGUgc3Vic2VxdWVudCBERUxFVEUuXG4gICAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgICAgIGV4dGVybmFsLmxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICByZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpZiBQaHlzaWNhbFJlc291cmNlSWQgaXMgbm90IHNwZWNpZmllZCwgc29tZXRoaW5nIGlzXG4gICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgZXh0ZXJuYWwubG9nKGBFUlJPUjogTWFsZm9ybWVkIGV2ZW50LiBcIlBoeXNpY2FsUmVzb3VyY2VJZFwiIGlzIHJlcXVpcmVkOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyB0aGlzIGlzIGFuIGFjdHVhbCBlcnJvciwgZmFpbCB0aGUgYWN0aXZpdHkgYWx0b2dldGhlciBhbmQgZXhpc3QuXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ0ZBSUxFRCcsIHJlc3ApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlbmRlclJlc3BvbnNlKFxuICBjZm5SZXF1ZXN0OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgeyBQaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmcgfSxcbiAgaGFuZGxlclJlc3BvbnNlOiB2b2lkIHwgSGFuZGxlclJlc3BvbnNlID0geyB9KTogUmVzcG9uc2Uge1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gaGFuZGxlclJlc3BvbnNlLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlJlcXVlc3RJZDtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke2hhbmRsZXJSZXNwb25zZS5QaHlzaWNhbFJlc291cmNlSWR9XCIgZHVyaW5nIGRlbGV0aW9uYCk7XG4gIH1cblxuICAvLyBtZXJnZSByZXF1ZXN0IGV2ZW50IGFuZCByZXN1bHQgZXZlbnQgKHJlc3VsdCBwcmV2YWlscykuXG4gIHJldHVybiB7XG4gICAgLi4uY2ZuUmVxdWVzdCxcbiAgICAuLi5oYW5kbGVyUmVzcG9uc2UsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN1Ym1pdFJlc3BvbnNlKHN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsIGV2ZW50OiBSZXNwb25zZSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogZXZlbnQuUmVhc29uID8/IHN0YXR1cyxcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IE1JU1NJTkdfUEhZU0lDQUxfSURfTUFSS0VSLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBOb0VjaG86IGV2ZW50Lk5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGV4dGVybmFsLmxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGNvbnN0IHJlcSA9IHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcmV0cnlPcHRpb25zID0ge1xuICAgIGF0dGVtcHRzOiA1LFxuICAgIHNsZWVwOiAxMDAwLFxuICB9O1xuICBhd2FpdCB3aXRoUmV0cmllcyhyZXRyeU9wdGlvbnMsIGV4dGVybmFsLnNlbmRIdHRwUmVxdWVzdCkocmVxLCByZXNwb25zZUJvZHkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U2VuZEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBfID0+IHJlc29sdmUoKSk7XG4gICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICByZXF1ZXN0LndyaXRlKHJlc3BvbnNlQm9keSk7XG4gICAgICByZXF1ZXN0LmVuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0TG9nKGZtdDogc3RyaW5nLCAuLi5wYXJhbXM6IGFueVtdKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGZtdCwgLi4ucGFyYW1zKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICAvKiogSG93IG1hbnkgcmV0cmllcyAod2lsbCBhdCBsZWFzdCB0cnkgb25jZSkgKi9cbiAgcmVhZG9ubHkgYXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIFNsZWVwIGJhc2UsIGluIG1zICovXG4gIHJlYWRvbmx5IHNsZWVwOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUmV0cmllczxBIGV4dGVuZHMgQXJyYXk8YW55PiwgQj4ob3B0aW9uczogUmV0cnlPcHRpb25zLCBmbjogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+KTogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+IHtcbiAgcmV0dXJuIGFzeW5jICguLi54czogQSkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IG9wdGlvbnMuYXR0ZW1wdHM7XG4gICAgbGV0IG1zID0gb3B0aW9ucy5zbGVlcDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZuKC4uLnhzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGF0dGVtcHRzLS0gPD0gMCkge1xuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbXMpKTtcbiAgICAgICAgbXMgKj0gMjtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js new file mode 100644 index 0000000000000..355c354b96ef3 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b/index.js @@ -0,0 +1,266 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handler = void 0; +/* eslint-disable no-console */ +/* eslint-disable import/no-extraneous-dependencies */ +const crypto_1 = require("crypto"); +const aws_sdk_1 = require("aws-sdk"); +// S3 handles cross-region redirection, can use a global API object +const s3 = new aws_sdk_1.S3(); +// KMS does not redirect across regions, requires a regional getter +const getKMSForRegion = (() => { + let kms; + return (region) => { + if (!kms || kms.config.region !== region) { + kms = new aws_sdk_1.KMS({ region }); + } + return kms; + }; +})(); +function checkSuccessOrLogResponse(resp) { + if (resp && resp.statusCode >= 200 && resp.statusCode <= 299) { + return true; + } + if (resp) { + console.log(`ERROR: ${resp.statusCode} ${resp.statusMessage}`); + console.log(resp.body.toString()); + } + else { + console.log('ERROR: no response'); + } + return false; +} +function generatePhysicalResourceId() { + return 'awscdk:distribution-policy-setter:' + (0, crypto_1.randomUUID)().replace('-', ''); +} +function generatePolicySid(physicalResourceId) { + const hash = physicalResourceId.split(':').at(-1); + return 'CDKDistributionPolicySetter' + hash?.toUpperCase(); +} +function parseArn(arn) { + const re = /^arn:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?[^:]+)?:(?.+)?$/; + return arn.match(re)?.groups ?? null; +} +// parses JSON into a BareMinimumPolicy, or throws an error +function parsePolicyJSON(str, context) { + if (!str) { + throw new Error('unable to fetch policy document for ' + context); + } + let parsed; + try { + parsed = JSON.parse(str); + } + catch { + throw new Error('unable to parse JSON policy document for ' + context); + } + // To maintain a good chance of forward-compatibility, this is a loose check: + // Version exists and is not too old for value references, and Statements is an + // array of objects each of which has an Effect string and maybe a Sid string. + if (typeof parsed !== 'object' || typeof parsed.Version !== 'string' || + parsed.Version.length != 10 || parsed.Version === '2008-10-17' || + !Array.isArray(parsed.Statement)) { + throw new Error('invalid JSON policy document for ' + context); + } + for (const s of parsed.Statement) { + if (typeof s !== 'object' || !('Effect' in s) || typeof s.Effect !== 'string') { + throw new Error('invalid JSON policy statement for ' + context); + } + if ('Sid' in s && typeof s.Sid !== 'string') { + throw new Error('invalid JSON policy statement for ' + context); + } + } + return parsed; +} +// replace properties of one Statement with another; returns false if nothing changed +function replacePropertiesWith(dst, src) { + let didAnything = false; + for (const k in dst) { + if (!(k in src)) { + delete dst[k]; + didAnything = true; + } + } + for (const k in src) { + if (!(k in dst) || JSON.stringify(dst[k]) !== JSON.stringify(src[k])) { + dst[k] = src[k]; + didAnything = true; + } + } + return didAnything; +} +// modifies array in place; returns false if no changes were made to statements +function addOrReplacePolicyStatement(s, desired, deleteOnly, context) { + const found = s.map((_, i) => i).filter(i => s[i].Sid === desired.Sid); + if (found.length > 1) { + throw new Error('duplicate Sid in JSON policy document for ' + context); + } + if (deleteOnly) { + if (found.length == 1) { + s.splice(found[0], 1); + return true; + } + else { + return false; + } + } + else { + if (found.length == 1) { + return replacePropertiesWith(s[found[0]], desired); + } + s.push(desired); + return true; + } +} +async function lookupDistributionLogicalIdFromArn(distArn, stackId) { + const distId = distArn.split('distribution/').at(-1); + if (!distId || !distId.match(/^[0-9A-Z]+$/)) { + throw new Error('invalid distribution arn ' + distArn); + } + const cf = new aws_sdk_1.CloudFormation({ apiVersion: '2010-05-15', region: parseArn(stackId)?.region }); + const describe = await cf.describeStackResources({ PhysicalResourceId: distId }).promise(); + if (!checkSuccessOrLogResponse(describe.$response.httpResponse)) { + throw new Error('unable to call describeStackResources on distribution id'); + } + const found = describe.StackResources?.find(e => e.ResourceType === 'AWS::CloudFront::Distribution' && e.StackId === stackId); + return found?.LogicalResourceId ?? null; +} +async function processArns(uniqueSid, distribution, arnsRO, arnsRW, deleteOnly, tagNameRO, tagNameRW) { + for (const dryRun of [true, false]) { + const pairWith = (b) => ((e) => [e, b]); + const mapped = arnsRO.map(pairWith(false)).concat(arnsRW.map(pairWith(true))); + for (const [arn, writeAccess] of mapped) { + console.log('processing ' + arn + (writeAccess ? ' (read-write)' : ' (read-only)') + (dryRun ? ' [DRY RUN]' : '')); + const arnParts = parseArn(arn); + if (!arnParts) { + throw new Error('unparseable arn ' + arn); + } + const arnResource = arnParts.resource ?? ''; + const safetyCheckTag = writeAccess ? + ((k) => k === tagNameRW) : + ((k) => k === tagNameRW || k === tagNameRO); + if (arnParts.service === 's3' && arnResource.length > 0 && !arnResource.includes('/')) { + const s3tags = await s3.getBucketTagging({ Bucket: arnResource }).promise(); + if (!checkSuccessOrLogResponse(s3tags.$response.httpResponse)) { + throw new Error('unable to verify distribution safety-check tag for ' + arn); + } + const foundtag = s3tags?.TagSet?.map(e => e.Key)?.find(safetyCheckTag); + if (!foundtag) { + throw new Error('no matching distribution safety-check tag for ' + arn); + } + console.log('verified distribution safety-check tag ' + foundtag + ' for ' + arn); + const desired = { + Sid: uniqueSid, + Effect: 'Allow', + Principal: { Service: 'cloudfront.amazonaws.com' }, + Action: writeAccess ? ['s3:GetObject', 's3:PutObject'] : 's3:GetObject', + Resource: arn + '/*', + Condition: { StringEquals: { 'aws:SourceArn': distribution } }, + }; + const get = await s3.getBucketPolicy({ Bucket: arnResource }).promise(); + const parsed = parsePolicyJSON(get.Policy, arn); + if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { + const put = await s3.putBucketPolicy({ Bucket: arnResource, Policy: JSON.stringify(parsed) }).promise(); + if (!checkSuccessOrLogResponse(put.$response.httpResponse)) { + throw new Error('unable to put new JSON policy document for ' + arn); + } + console.log('successfully modified ' + arn); + } + } + else if (arnParts.service === 'kms' && arnParts.region && arnResource.startsWith('key/')) { + const kms = getKMSForRegion(arnParts.region); + for (let marker = undefined;;) { + const kmstags = await kms.listResourceTags({ KeyId: arn, Marker: marker }).promise(); + if (!checkSuccessOrLogResponse(kmstags.$response.httpResponse)) { + throw new Error('unable to verify distribution safety-check tag for ' + arn); + } + const foundkey = kmstags.Tags?.map(e => e.TagKey)?.find(safetyCheckTag); + if (foundkey) { + console.log('verified distribution safety-check tag ' + foundkey + ' for ' + arn); + break; + } + if (!kmstags.Truncated || !kmstags.NextMarker) { + throw new Error('no matching distribution safety-check tag for ' + arn); + } + } + const desired = { + Sid: uniqueSid, + Effect: 'Allow', + Principal: { Service: 'cloudfront.amazonaws.com' }, + Action: writeAccess ? ['kms:Decrypt', 'kms:Encrypt', 'kms:GetDataKey*'] : 'kms:Decrypt', + Resource: arn, + Condition: { StringEquals: { 'aws:SourceArn': distribution } }, + }; + const get = await kms.getKeyPolicy({ KeyId: arn, PolicyName: 'default' }).promise(); + const parsed = parsePolicyJSON(get.Policy, arn); + if (addOrReplacePolicyStatement(parsed.Statement, desired, deleteOnly, arn) && !dryRun) { + const put = await kms.putKeyPolicy({ KeyId: arn, PolicyName: 'default', Policy: JSON.stringify(parsed) }).promise(); + if (!checkSuccessOrLogResponse(put.$response.httpResponse)) { + throw new Error('unable to put new JSON policy document for ' + arn); + } + console.log('successfully modified ' + arn); + } + } + else { + throw new Error('unknown service for ' + arn); + } + } + } +} +async function handler(event) { + function isStringArray(x) { + return Array.isArray(x) && x.every(e => typeof e === 'string'); + } + const dist = event.ResourceProperties.distribution; + const arnsRO = event.ResourceProperties.readOnlyArns; + const arnsRW = event.ResourceProperties.readWriteArns; + if (typeof dist !== 'string' || !dist.startsWith('arn:aws:cloudfront:')) { + throw new Error('invalid distribution property'); + } + if (!isStringArray(arnsRO) || !arnsRO.every(parseArn)) { + throw new Error('invalid readOnlyArns property'); + } + if (!isStringArray(arnsRW) || !arnsRW.every(parseArn)) { + throw new Error('invalid readWriteArns property'); + } + const account = parseArn(event.ServiceToken)?.account; + if (!account || parseArn(dist)?.account !== account) { + throw new Error('invalid cross-account permission grant'); + } + let physicalId = String(event.PhysicalResourceId ?? generatePhysicalResourceId()); + // If updating and params have changed, replace the physical ID + // to trigger a CloudFormation Delete request for the previous ID + // when (and if) the update succeeds - a safe two-phase commit. + if (event.RequestType === 'Update') { + const update = event; + const olddist = update.OldResourceProperties.distribution ?? ''; + const oldarnsRO = update.OldResourceProperties.readOnlyArns ?? []; + const oldarnsRW = update.OldResourceProperties.readWriteArns ?? []; + if (JSON.stringify([dist, arnsRO, arnsRW]) !== JSON.stringify([olddist, oldarnsRO, oldarnsRW])) { + console.log('parameters changed, generating new physical id'); + physicalId = generatePhysicalResourceId(); + } + } + // Look up logical ID from distribution ID, verify against our stack ID + const distLogicalId = await lookupDistributionLogicalIdFromArn(dist, event.StackId); + if (!distLogicalId) { + throw new Error('unable to locate distribution in stack'); + } + // NOTE: This logic must be duplicated exactly from computeSafetyCheckTagName + const safetyCheckText = process.env.CDK_STACK_NAME + '|' + distLogicalId; + const safetyCheckHash = (0, crypto_1.createHash)('sha256').update(safetyCheckText).digest('hex').slice(-32); + const tagNameRO = `aws-cdk:grant-distribution-ro:${safetyCheckHash}`; + const tagNameRW = `aws-cdk:grant-distribution-rw:${safetyCheckHash}`; + const dedupeSet = new Set(); + const hasNeverSeen = (e) => !dedupeSet.has(e) && !!dedupeSet.add(e); + // Process arnsRW first in case an ARN appears in both arnsRW and arnsRO + const dedupedRW = arnsRW.filter(hasNeverSeen); + const dedupedRO = arnsRO.filter(hasNeverSeen); + const policySid = generatePolicySid(physicalId); + const deleteOnly = event.RequestType === 'Delete'; + await processArns(policySid, dist, dedupedRO, dedupedRW, deleteOnly, tagNameRO, tagNameRW); + return { + PhysicalResourceId: physicalId, + }; +} +exports.handler = handler; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0Isc0RBQXNEO0FBQ3RELG1DQUFnRDtBQUNoRCxxQ0FBZ0U7QUFFaEUsbUVBQW1FO0FBQ25FLE1BQU0sRUFBRSxHQUFHLElBQUksWUFBRSxFQUFFLENBQUM7QUFFcEIsbUVBQW1FO0FBQ25FLE1BQU0sZUFBZSxHQUFHLENBQUMsR0FBRyxFQUFFO0lBQzVCLElBQUksR0FBb0IsQ0FBQztJQUN6QixPQUFPLENBQUMsTUFBYyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxNQUFNLEVBQUU7WUFDeEMsR0FBRyxHQUFHLElBQUksYUFBRyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztTQUMzQjtRQUNELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQXdCTCxTQUFTLHlCQUF5QixDQUFDLElBQXFDO0lBQ3RFLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksR0FBRyxFQUFFO1FBQzVELE9BQU8sSUFBSSxDQUFDO0tBQ2I7SUFDRCxJQUFJLElBQUksRUFBRTtRQUNSLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0tBQ25DO1NBQU07UUFDTCxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixDQUFDLENBQUM7S0FDbkM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxTQUFTLDBCQUEwQjtJ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QUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDOUMsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUU5QyxNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNoRCxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsQ0FBQztJQUNsRCxNQUFNLFdBQVcsQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUUzRixPQUFPO1FBQ0wsa0JBQWtCLEVBQUUsVUFBVTtLQUMvQixDQUFDO0FBQ0osQ0FBQztBQWpFRCwwQkFpRUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG4vKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXMgKi9cbmltcG9ydCB7IGNyZWF0ZUhhc2gsIHJhbmRvbVVVSUQgfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgQ2xvdWRGb3JtYXRpb24sIEh0dHBSZXNwb25zZSwgS01TLCBTMyB9IGZyb20gJ2F3cy1zZGsnO1xuXG4vLyBTMyBoYW5kbGVzIGNyb3NzLXJlZ2lvbiByZWRpcmVjdGlvbiwgY2FuIHVzZSBhIGdsb2JhbCBBUEkgb2JqZWN0XG5jb25zdCBzMyA9IG5ldyBTMygpO1xuXG4vLyBLTVMgZG9lcyBub3QgcmVkaXJlY3QgYWNyb3NzIHJlZ2lvbnMsIHJlcXVpcmVzIGEgcmVnaW9uYWwgZ2V0dGVyXG5jb25zdCBnZXRLTVNGb3JSZWdpb24gPSAoKCkgPT4ge1xuICBsZXQga21zOiBLTVMgfCB1bmRlZmluZWQ7XG4gIHJldHVybiAocmVnaW9uOiBzdHJpbmcpID0+IHtcbiAgICBpZiAoIWttcyB8fCBrbXMuY29uZmlnLnJlZ2lvbiAhPT0gcmVnaW9uKSB7XG4gICAgICBrbXMgPSBuZXcgS01TKHsgcmVnaW9uIH0pO1xuICAgIH1cbiAgICByZXR1cm4ga21zO1xuICB9O1xufSkoKTtcblxuLy8gV2UgYXJlIG5vdCB0cnlpbmcgdG8gZG8gYSBjb21wbGV0ZSBwYXJzZSBvZiB0aGUgUG9saWN5IGZpZWxkcztcbi8vIHdlIG9ubHkgdmVyaWZ5IGVub3VnaCBvZiB0aGUgdHlwZSB0byBzYWZlbHkgbWFrZSBtb2RpZmljYXRpb25zLlxuaW50ZXJmYWNlIEJhcmVNaW5pbXVtU3RhdGVtZW50IHtcbiAgU2lkPzogc3RyaW5nO1xuICBba2V5OiBzdHJpbmddOiBhbnk7XG59XG5pbnRlcmZhY2UgQmFyZU1pbmltdW1Qb2xpY3kge1xuICBWZXJzaW9uOiBzdHJpbmc7XG4gIFN0YXRlbWVudDogQmFyZU1pbmltdW1TdGF0ZW1lbnRbXTtcbiAgW2tleTogc3RyaW5nXTogYW55O1xufVxuXG4vLyBXZSBhcmUgYSBsb3Qgc3RyaWN0ZXIgYWJvdXQgb3VyIG93biBnZW5lcmF0ZWQgc3RhdGVtZW50c1xuaW50ZXJmYWNlIFBlcm1pc3Npb25HcmFudFN0YXRlbWVudCB7XG4gIFNpZDogc3RyaW5nO1xuICBFZmZlY3Q6ICdBbGxvdyc7XG4gIFByaW5jaXBhbDogeyBTZXJ2aWNlOiAnY2xvdWRmcm9udC5hbWF6b25hd3MuY29tJyB9O1xuICBBY3Rpb246IHN0cmluZyB8IHN0cmluZ1tdO1xuICBSZXNvdXJjZTogc3RyaW5nIHwgc3RyaW5nW107XG4gIENvbmRpdGlvbjogeyBTdHJpbmdFcXVhbHM6IHsgJ2F3czpTb3VyY2VBcm4nOiBzdHJpbmcgfSB9O1xufVxuXG5mdW5jdGlvbiBjaGVja1N1Y2Nlc3NPckxvZ1Jlc3BvbnNlKHJlc3A6IEh0dHBSZXNwb25zZSB8IHVuZGVmaW5lZCB8IG51bGwpIHtcbiAgaWYgKHJlc3AgJiYgcmVzcC5zdGF0dXNDb2RlID49IDIwMCAmJiByZXNwLnN0YXR1c0NvZGUgPD0gMjk5KSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgaWYgKHJlc3ApIHtcbiAgICBjb25zb2xlLmxvZyhgRVJST1I6ICR7cmVzcC5zdGF0dXNDb2RlfSAke3Jlc3Auc3RhdHVzTWVzc2FnZX1gKTtcbiAgICBjb25zb2xlLmxvZyhyZXNwLmJvZHkudG9TdHJpbmcoKSk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coJ0VSUk9SOiBubyByZXNwb25zZScpO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVQaHlzaWNhbFJlc291cmNlSWQoKSB7XG4gIHJldHVybiAnYXdzY2RrOmRpc3RyaWJ1dGlvbi1wb2xpY3ktc2V0dGVyOicgKyByYW5kb21VVUlEKCkucmVwbGFjZSgnLScsICcnKTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVQb2xpY3lTaWQocGh5c2ljYWxSZXNvdXJjZUlkOiBzdHJpbmcpIHtcbiAgY29uc3QgaGFzaCA9IHBoeXNpY2FsUmVzb3VyY2VJZC5zcGxpdCgnOicpLmF0KC0xKTtcbiAgcmV0dXJuICdDREtEaXN0cmlidXRpb25Qb2xpY3lTZXR0ZXInICsgaGFzaD8udG9VcHBlckNhc2UoKTtcbn1cblxuaW50ZXJmYWNlIFBhcnNlZEFybiB7XG4gIHBhcnRpdGlvbj86IHN0cmluZztcbiAgc2VydmljZT86IHN0cmluZztcbiAgcmVnaW9uPzogc3RyaW5nO1xuICBhY2NvdW50Pzogc3RyaW5nLFxuICByZXNvdXJjZT86IHN0cmluZztcbn1cbmZ1bmN0aW9uIHBhcnNlQXJuKGFybjogc3RyaW5nKSA6IFBhcnNlZEFybiB8IG51bGwge1xuICBjb25zdCByZSA9IC9eYXJuOig/PHBhcnRpdGlvbj5bXjpdKyk/Oig/PHNlcnZpY2U+W146XSspPzooPzxyZWdpb24+W146XSspPzooPzxhY2NvdW50PlteOl0rKT86KD88cmVzb3VyY2U+LispPyQvO1xuICByZXR1cm4gYXJuLm1hdGNoKHJlKT8uZ3JvdXBzID8/IG51bGw7XG59XG5cbi8vIHBhcnNlcyBKU09OIGludG8gYSBCYXJlTWluaW11bVBvbGljeSwgb3IgdGhyb3dzIGFuIGVycm9yXG5mdW5jdGlvbiBwYXJzZVBvbGljeUpTT04oc3RyOiBzdHJpbmcgfCB1bmRlZmluZWQsIGNvbnRleHQ6IHN0cmluZykge1xuICBpZiAoIXN0cikge1xuICAgIHRocm93IG5ldyBFcnJvcigndW5hYmxlIHRvIGZldGNoIHBvbGljeSBkb2N1bWVudCBmb3IgJyArIGNvbnRleHQpO1xuICB9XG4gIGxldCBwYXJzZWQ6IGFueTtcbiAgdHJ5IHtcbiAgICBwYXJzZWQgPSBKU09OLnBhcnNlKHN0cik7XG4gIH0gY2F0Y2gge1xuICAgIHRocm93IG5ldyBFcnJvcigndW5hYmxlIHRvIHBhcnNlIEpTT04gcG9saWN5IGRvY3VtZW50IGZvciAnICsgY29udGV4dCk7XG4gIH1cbiAgLy8gVG8gbWFpbnRhaW4gYSBnb29kIGNoYW5jZSBvZiBmb3J3YXJkLWNvbXBhdGliaWxpdHksIHRoaXMgaXMgYSBsb29zZSBjaGVjazpcbiAgLy8gVmVyc2lvbiBleGlzdHMgYW5kIGlzIG5vdCB0b28gb2xkIGZvciB2YWx1ZSByZWZlcmVuY2VzLCBhbmQgU3RhdGVtZW50cyBpcyBhblxuICAvLyBhcnJheSBvZiBvYmplY3RzIGVhY2ggb2Ygd2hpY2ggaGFzIGFuIEVmZmVjdCBzdHJpbmcgYW5kIG1heWJlIGEgU2lkIHN0cmluZy5cbiAgaWYgKHR5cGVvZiBwYXJzZWQgIT09ICdvYmplY3QnIHx8IHR5cGVvZiBwYXJzZWQuVmVyc2lvbiAhPT0gJ3N0cmluZycgfHxcbiAgICAgIHBhcnNlZC5WZXJzaW9uLmxlbmd0aCAhPSAxMCB8fCBwYXJzZWQuVmVyc2lvbiA9PT0gJzIwMDgtMTAtMTcnIHx8XG4gICAgICAhQXJyYXkuaXNBcnJheShwYXJzZWQuU3RhdGVtZW50KSApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgSlNPTiBwb2xpY3kgZG9jdW1lbnQgZm9yICcgKyBjb250ZXh0KTtcbiAgfVxuICBmb3IgKGNvbnN0IHMgb2YgcGFyc2VkLlN0YXRlbWVudCkge1xuICAgIGlmICh0eXBlb2YgcyAhPT0gJ29iamVjdCcgfHwgISgnRWZmZWN0JyBpbiBzKSB8fCB0eXBlb2Ygcy5FZmZlY3QgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgSlNPTiBwb2xpY3kgc3RhdGVtZW50IGZvciAnICsgY29udGV4dCk7XG4gICAgfVxuICAgIGlmICgnU2lkJyBpbiBzICYmIHR5cGVvZiBzLlNpZCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBKU09OIHBvbGljeSBzdGF0ZW1lbnQgZm9yICcgKyBjb250ZXh0KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHBhcnNlZCBhcyBCYXJlTWluaW11bVBvbGljeTtcbn1cblxuLy8gcmVwbGFjZSBwcm9wZXJ0aWVzIG9mIG9uZSBTdGF0ZW1lbnQgd2l0aCBhbm90aGVyOyByZXR1cm5zIGZhbHNlIGlmIG5vdGhpbmcgY2hhbmdlZFxuZnVuY3Rpb24gcmVwbGFjZVByb3BlcnRpZXNXaXRoKGRzdDogQmFyZU1pbmltdW1TdGF0ZW1lbnQsIHNyYzogQmFyZU1pbmltdW1TdGF0ZW1lbnQpIHtcbiAgbGV0IGRpZEFueXRoaW5nID0gZmFsc2U7XG4gIGZvciAoY29uc3QgayBpbiBkc3QpIHtcbiAgICBpZiAoIShrIGluIHNyYykpIHtcbiAgICAgIGRlbGV0ZSBkc3Rba107XG4gICAgICBkaWRBbnl0aGluZyA9IHRydWU7XG4gICAgfVxuICB9XG4gIGZvciAoY29uc3QgayBpbiBzcmMpIHtcbiAgICBpZiAoIShrIGluIGRzdCkgfHwgSlNPTi5zdHJpbmdpZnkoZHN0W2tdKSAhPT0gSlNPTi5zdHJpbmdpZnkoc3JjW2tdKSkge1xuICAgICAgZHN0W2tdID0gc3JjW2tdO1xuICAgICAgZGlkQW55dGhpbmcgPSB0cnVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZGlkQW55dGhpbmc7XG59XG5cbi8vIG1vZGlmaWVzIGFycmF5IGluIHBsYWNlOyByZXR1cm5zIGZhbHNlIGlmIG5vIGNoYW5nZXMgd2VyZSBtYWRlIHRvIHN0YXRlbWVudHNcbmZ1bmN0aW9uIGFkZE9yUmVwbGFjZVBvbGljeVN0YXRlbWVudChcbiAgczogQmFyZU1pbmltdW1TdGF0ZW1lbnRbXSxcbiAgZGVzaXJlZDogQmFyZU1pbmltdW1TdGF0ZW1lbnQgJiBQZXJtaXNzaW9uR3JhbnRTdGF0ZW1lbnQsXG4gIGRlbGV0ZU9ubHk6IGJvb2xlYW4sXG4gIGNvbnRleHQ6IHN0cmluZyxcbikge1xuICBjb25zdCBmb3VuZCA9IHMubWFwKChfLCBpKSA9PiBpKS5maWx0ZXIoaSA9PiBzW2ldLlNpZCA9PT0gZGVzaXJlZC5TaWQpO1xuICBpZiAoZm91bmQubGVuZ3RoID4gMSkge1xuICAgIHRocm93IG5ldyBFcnJvcignZHVwbGljYXRlIFNpZCBpbiBKU09OIHBvbGljeSBkb2N1bWVudCBmb3IgJyArIGNvbnRleHQpO1xuICB9XG4gIGlmIChkZWxldGVPbmx5KSB7XG4gICAgaWYgKGZvdW5kLmxlbmd0aCA9PSAxKSB7XG4gICAgICBzLnNwbGljZShmb3VuZFswXSwgMSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBpZiAoZm91bmQubGVuZ3RoID09IDEpIHtcbiAgICAgIHJldHVybiByZXBsYWNlUHJvcGVydGllc1dpdGgoc1tmb3VuZFswXV0sIGRlc2lyZWQpO1xuICAgIH1cbiAgICBzLnB1c2goZGVzaXJlZCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gbG9va3VwRGlzdHJpYnV0aW9uTG9naWNhbElkRnJvbUFybihkaXN0QXJuOiBzdHJpbmcsIHN0YWNrSWQ6IHN0cmluZykge1xuICBjb25zdCBkaXN0SWQgPSBkaXN0QXJuLnNwbGl0KCdkaXN0cmlidXRpb24vJykuYXQoLTEpO1xuICBpZiAoIWRpc3RJZCB8fCAhZGlzdElkLm1hdGNoKC9eWzAtOUEtWl0rJC8pKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGRpc3RyaWJ1dGlvbiBhcm4gJyArIGRpc3RBcm4pO1xuICB9XG4gIGNvbnN0IGNmID0gbmV3IENsb3VkRm9ybWF0aW9uKHsgYXBpVmVyc2lvbjogJzIwMTAtMDUtMTUnLCByZWdpb246IHBhcnNlQXJuKHN0YWNrSWQpPy5yZWdpb24gfSk7XG4gIGNvbnN0IGRlc2NyaWJlID0gYXdhaXQgY2YuZGVzY3JpYmVTdGFja1Jlc291cmNlcyh7IFBoeXNpY2FsUmVzb3VyY2VJZDogZGlzdElkIH0pLnByb21pc2UoKTtcbiAgaWYgKCFjaGVja1N1Y2Nlc3NPckxvZ1Jlc3BvbnNlKGRlc2NyaWJlLiRyZXNwb25zZS5odHRwUmVzcG9uc2UpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCd1bmFibGUgdG8gY2FsbCBkZXNjcmliZVN0YWNrUmVzb3VyY2VzIG9uIGRpc3RyaWJ1dGlvbiBpZCcpO1xuICB9XG4gIGNvbnN0IGZvdW5kID0gZGVzY3JpYmUuU3RhY2tSZXNvdXJjZXM/LmZpbmQoXG4gICAgZSA9PiBlLlJlc291cmNlVHlwZSA9PT0gJ0FXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uJyAmJiBlLlN0YWNrSWQgPT09IHN0YWNrSWQsXG4gICk7XG4gIHJldHVybiBmb3VuZD8uTG9naWNhbFJlc291cmNlSWQgPz8gbnVsbDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0FybnMoXG4gIHVuaXF1ZVNpZDogc3RyaW5nLFxuICBkaXN0cmlidXRpb246IHN0cmluZyxcbiAgYXJuc1JPOiBzdHJpbmdbXSxcbiAgYXJuc1JXOiBzdHJpbmdbXSxcbiAgZGVsZXRlT25seTogYm9vbGVhbixcbiAgdGFnTmFtZVJPOiBzdHJpbmcsXG4gIHRhZ05hbWVSVzogc3RyaW5nLFxuKSB7XG4gIGZvciAoY29uc3QgZHJ5UnVuIG9mIFt0cnVlLCBmYWxzZV0pIHtcbiAgICBjb25zdCBwYWlyV2l0aCA9IChiOmJvb2xlYW4pID0+ICgoZTogc3RyaW5nKTogW3N0cmluZywgYm9vbGVhbl0gPT4gW2UsIGJdKTtcbiAgICBjb25zdCBtYXBwZWQgPSBhcm5zUk8ubWFwKHBhaXJXaXRoKGZhbHNlKSkuY29uY2F0KGFybnNSVy5tYXAocGFpcldpdGgodHJ1ZSkpKTtcbiAgICBmb3IgKGNvbnN0IFthcm4sIHdyaXRlQWNjZXNzXSBvZiBtYXBwZWQpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdwcm9jZXNzaW5nICcgKyBhcm4gKyAod3JpdGVBY2Nlc3MgPyAnIChyZWFkLXdyaXRlKScgOiAnIChyZWFkLW9ubHkpJykgKyAoZHJ5UnVuID8gJyBbRFJZIFJVTl0nIDogJycpKTtcblxuICAgICAgY29uc3QgYXJuUGFydHMgPSBwYXJzZUFybihhcm4pO1xuICAgICAgaWYgKCFhcm5QYXJ0cykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VucGFyc2VhYmxlIGFybiAnICsgYXJuKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGFyblJlc291cmNlID0gYXJuUGFydHMucmVzb3VyY2UgPz8gJyc7XG5cbiAgICAgIGNvbnN0IHNhZmV0eUNoZWNrVGFnID0gd3JpdGVBY2Nlc3MgP1xuICAgICAgICAoKGs6IHN0cmluZykgPT4gayA9PT0gdGFnTmFtZVJXKSA6XG4gICAgICAgICgoazogc3RyaW5nKSA9PiBrID09PSB0YWdOYW1lUlcgfHwgayA9PT0gdGFnTmFtZVJPKTtcblxuICAgICAgaWYgKGFyblBhcnRzLnNlcnZpY2UgPT09ICdzMycgJiYgYXJuUmVzb3VyY2UubGVuZ3RoID4gMCAmJiAhYXJuUmVzb3VyY2UuaW5jbHVkZXMoJy8nKSkge1xuICAgICAgICBjb25zdCBzM3RhZ3MgPSBhd2FpdCBzMy5nZXRCdWNrZXRUYWdnaW5nKHsgQnVja2V0OiBhcm5SZXNvdXJjZSB9KS5wcm9taXNlKCk7XG4gICAgICAgIGlmICghY2hlY2tTdWNjZXNzT3JMb2dSZXNwb25zZShzM3RhZ3MuJHJlc3BvbnNlLmh0dHBSZXNwb25zZSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuYWJsZSB0byB2ZXJpZnkgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgZm9yICcgKyBhcm4pO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGZvdW5kdGFnID0gczN0YWdzPy5UYWdTZXQ/Lm1hcChlID0+IGUuS2V5KT8uZmluZChzYWZldHlDaGVja1RhZyk7XG4gICAgICAgIGlmICghZm91bmR0YWcpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vIG1hdGNoaW5nIGRpc3RyaWJ1dGlvbiBzYWZldHktY2hlY2sgdGFnIGZvciAnICsgYXJuKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZygndmVyaWZpZWQgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgJyArIGZvdW5kdGFnICsgJyBmb3IgJyArIGFybik7XG5cbiAgICAgICAgY29uc3QgZGVzaXJlZDogUGVybWlzc2lvbkdyYW50U3RhdGVtZW50ID0ge1xuICAgICAgICAgIFNpZDogdW5pcXVlU2lkLFxuICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICBQcmluY2lwYWw6IHsgU2VydmljZTogJ2Nsb3VkZnJvbnQuYW1hem9uYXdzLmNvbScgfSxcbiAgICAgICAgICBBY3Rpb246IHdyaXRlQWNjZXNzID8gWydzMzpHZXRPYmplY3QnLCAnczM6UHV0T2JqZWN0J10gOiAnczM6R2V0T2JqZWN0JyxcbiAgICAgICAgICBSZXNvdXJjZTogYXJuICsgJy8qJyxcbiAgICAgICAgICBDb25kaXRpb246IHsgU3RyaW5nRXF1YWxzOiB7ICdhd3M6U291cmNlQXJuJzogZGlzdHJpYnV0aW9uIH0gfSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgZ2V0ID0gYXdhaXQgczMuZ2V0QnVja2V0UG9saWN5KHsgQnVja2V0OiBhcm5SZXNvdXJjZSB9KS5wcm9taXNlKCk7XG4gICAgICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlUG9saWN5SlNPTihnZXQuUG9saWN5LCBhcm4pO1xuICAgICAgICBpZiAoYWRkT3JSZXBsYWNlUG9saWN5U3RhdGVtZW50KHBhcnNlZC5TdGF0ZW1lbnQsIGRlc2lyZWQsIGRlbGV0ZU9ubHksIGFybikgJiYgIWRyeVJ1bikge1xuICAgICAgICAgIGNvbnN0IHB1dCA9IGF3YWl0IHMzLnB1dEJ1Y2tldFBvbGljeSh7IEJ1Y2tldDogYXJuUmVzb3VyY2UsIFBvbGljeTogSlNPTi5zdHJpbmdpZnkocGFyc2VkKSB9KS5wcm9taXNlKCk7XG4gICAgICAgICAgaWYgKCFjaGVja1N1Y2Nlc3NPckxvZ1Jlc3BvbnNlKHB1dC4kcmVzcG9uc2UuaHR0cFJlc3BvbnNlKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmFibGUgdG8gcHV0IG5ldyBKU09OIHBvbGljeSBkb2N1bWVudCBmb3IgJyArIGFybik7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnNvbGUubG9nKCdzdWNjZXNzZnVsbHkgbW9kaWZpZWQgJyArIGFybik7XG4gICAgICAgIH1cblxuICAgICAgfSBlbHNlIGlmIChhcm5QYXJ0cy5zZXJ2aWNlID09PSAna21zJyAmJiBhcm5QYXJ0cy5yZWdpb24gJiYgYXJuUmVzb3VyY2Uuc3RhcnRzV2l0aCgna2V5LycpKSB7XG4gICAgICAgIGNvbnN0IGttcyA9IGdldEtNU0ZvclJlZ2lvbihhcm5QYXJ0cy5yZWdpb24pO1xuXG4gICAgICAgIGZvciAobGV0IG1hcmtlciA9IHVuZGVmaW5lZDs7KSB7XG4gICAgICAgICAgY29uc3Qga21zdGFncyA9IGF3YWl0IGttcy5saXN0UmVzb3VyY2VUYWdzKHsgS2V5SWQ6IGFybiwgTWFya2VyOiBtYXJrZXIgfSkucHJvbWlzZSgpO1xuICAgICAgICAgIGlmICghY2hlY2tTdWNjZXNzT3JMb2dSZXNwb25zZShrbXN0YWdzLiRyZXNwb25zZS5odHRwUmVzcG9uc2UpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuYWJsZSB0byB2ZXJpZnkgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgZm9yICcgKyBhcm4pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBmb3VuZGtleSA9IGttc3RhZ3MuVGFncz8ubWFwKGUgPT4gZS5UYWdLZXkpPy5maW5kKHNhZmV0eUNoZWNrVGFnKTtcbiAgICAgICAgICBpZiAoZm91bmRrZXkpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCd2ZXJpZmllZCBkaXN0cmlidXRpb24gc2FmZXR5LWNoZWNrIHRhZyAnICsgZm91bmRrZXkgKyAnIGZvciAnICsgYXJuKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoIWttc3RhZ3MuVHJ1bmNhdGVkIHx8ICFrbXN0YWdzLk5leHRNYXJrZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm8gbWF0Y2hpbmcgZGlzdHJpYnV0aW9uIHNhZmV0eS1jaGVjayB0YWcgZm9yICcgKyBhcm4pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRlc2lyZWQ6IFBlcm1pc3Npb25HcmFudFN0YXRlbWVudCA9IHtcbiAgICAgICAgICBTaWQ6IHVuaXF1ZVNpZCxcbiAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgUHJpbmNpcGFsOiB7IFNlcnZpY2U6ICdjbG91ZGZyb250LmFtYXpvbmF3cy5jb20nIH0sXG4gICAgICAgICAgQWN0aW9uOiB3cml0ZUFjY2VzcyA/IFsna21zOkRlY3J5cHQnLCAna21zOkVuY3J5cHQnLCAna21zOkdldERhdGFLZXkqJ10gOiAna21zOkRlY3J5cHQnLFxuICAgICAgICAgIFJlc291cmNlOiBhcm4sXG4gICAgICAgICAgQ29uZGl0aW9uOiB7IFN0cmluZ0VxdWFsczogeyAnYXdzOlNvdXJjZUFybic6IGRpc3RyaWJ1dGlvbiB9IH0sXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGdldCA9IGF3YWl0IGttcy5nZXRLZXlQb2xpY3koeyBLZXlJZDogYXJuLCBQb2xpY3lOYW1lOiAnZGVmYXVsdCcgfSkucHJvbWlzZSgpO1xuICAgICAgICBjb25zdCBwYXJzZWQgPSBwYXJzZVBvbGljeUpTT04oZ2V0LlBvbGljeSwgYXJuKTtcbiAgICAgICAgaWYgKGFkZE9yUmVwbGFjZVBvbGljeVN0YXRlbWVudChwYXJzZWQuU3RhdGVtZW50LCBkZXNpcmVkLCBkZWxldGVPbmx5LCBhcm4pICYmICFkcnlSdW4pIHtcbiAgICAgICAgICBjb25zdCBwdXQgPSBhd2FpdCBrbXMucHV0S2V5UG9saWN5KHsgS2V5SWQ6IGFybiwgUG9saWN5TmFtZTogJ2RlZmF1bHQnLCBQb2xpY3k6IEpTT04uc3RyaW5naWZ5KHBhcnNlZCkgfSkucHJvbWlzZSgpO1xuICAgICAgICAgIGlmICghY2hlY2tTdWNjZXNzT3JMb2dSZXNwb25zZShwdXQuJHJlc3BvbnNlLmh0dHBSZXNwb25zZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndW5hYmxlIHRvIHB1dCBuZXcgSlNPTiBwb2xpY3kgZG9jdW1lbnQgZm9yICcgKyBhcm4pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zb2xlLmxvZygnc3VjY2Vzc2Z1bGx5IG1vZGlmaWVkICcgKyBhcm4pO1xuICAgICAgICB9XG5cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndW5rbm93biBzZXJ2aWNlIGZvciAnICsgYXJuKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQpIHtcblxuICBmdW5jdGlvbiBpc1N0cmluZ0FycmF5KHg6IGFueSkgOiB4IGlzIHN0cmluZ1tdIHtcbiAgICByZXR1cm4gQXJyYXkuaXNBcnJheSh4KSAmJiB4LmV2ZXJ5KGUgPT4gdHlwZW9mIGUgPT09ICdzdHJpbmcnKTtcbiAgfVxuXG4gIGNvbnN0IGRpc3QgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuZGlzdHJpYnV0aW9uO1xuICBjb25zdCBhcm5zUk8gPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMucmVhZE9ubHlBcm5zO1xuICBjb25zdCBhcm5zUlcgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMucmVhZFdyaXRlQXJucztcbiAgaWYgKHR5cGVvZiBkaXN0ICE9PSAnc3RyaW5nJyB8fCAhZGlzdC5zdGFydHNXaXRoKCdhcm46YXdzOmNsb3VkZnJvbnQ6JykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgZGlzdHJpYnV0aW9uIHByb3BlcnR5Jyk7XG4gIH1cbiAgaWYgKCFpc1N0cmluZ0FycmF5KGFybnNSTykgfHwgIWFybnNSTy5ldmVyeShwYXJzZUFybikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgcmVhZE9ubHlBcm5zIHByb3BlcnR5Jyk7XG4gIH1cbiAgaWYgKCFpc1N0cmluZ0FycmF5KGFybnNSVykgfHwgIWFybnNSVy5ldmVyeShwYXJzZUFybikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgcmVhZFdyaXRlQXJucyBwcm9wZXJ0eScpO1xuICB9XG5cbiAgY29uc3QgYWNjb3VudCA9IHBhcnNlQXJuKGV2ZW50LlNlcnZpY2VUb2tlbik/LmFjY291bnQ7XG4gIGlmICghYWNjb3VudCB8fCBwYXJzZUFybihkaXN0KT8uYWNjb3VudCAhPT0gYWNjb3VudCkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBjcm9zcy1hY2NvdW50IHBlcm1pc3Npb24gZ3JhbnQnKTtcbiAgfVxuXG4gIGxldCBwaHlzaWNhbElkID0gU3RyaW5nKChldmVudCBhcyBhbnkpLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBnZW5lcmF0ZVBoeXNpY2FsUmVzb3VyY2VJZCgpKTtcblxuICAvLyBJZiB1cGRhdGluZyBhbmQgcGFyYW1zIGhhdmUgY2hhbmdlZCwgcmVwbGFjZSB0aGUgcGh5c2ljYWwgSURcbiAgLy8gdG8gdHJpZ2dlciBhIENsb3VkRm9ybWF0aW9uIERlbGV0ZSByZXF1ZXN0IGZvciB0aGUgcHJldmlvdXMgSURcbiAgLy8gd2hlbiAoYW5kIGlmKSB0aGUgdXBkYXRlIHN1Y2NlZWRzIC0gYSBzYWZlIHR3by1waGFzZSBjb21taXQuXG4gIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ1VwZGF0ZScpIHtcbiAgICBjb25zdCB1cGRhdGUgPSBldmVudCBhcyBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVVwZGF0ZUV2ZW50O1xuICAgIGNvbnN0IG9sZGRpc3QgPSB1cGRhdGUuT2xkUmVzb3VyY2VQcm9wZXJ0aWVzLmRpc3RyaWJ1dGlvbiA/PyAnJztcbiAgICBjb25zdCBvbGRhcm5zUk8gPSB1cGRhdGUuT2xkUmVzb3VyY2VQcm9wZXJ0aWVzLnJlYWRPbmx5QXJucyA/PyBbXTtcbiAgICBjb25zdCBvbGRhcm5zUlcgPSB1cGRhdGUuT2xkUmVzb3VyY2VQcm9wZXJ0aWVzLnJlYWRXcml0ZUFybnMgPz8gW107XG4gICAgaWYgKEpTT04uc3RyaW5naWZ5KFtkaXN0LCBhcm5zUk8sIGFybnNSV10pICE9PSBKU09OLnN0cmluZ2lmeShbb2xkZGlzdCwgb2xkYXJuc1JPLCBvbGRhcm5zUlddKSkge1xuICAgICAgY29uc29sZS5sb2coJ3BhcmFtZXRlcnMgY2hhbmdlZCwgZ2VuZXJhdGluZyBuZXcgcGh5c2ljYWwgaWQnKTtcbiAgICAgIHBoeXNpY2FsSWQgPSBnZW5lcmF0ZVBoeXNpY2FsUmVzb3VyY2VJZCgpO1xuICAgIH1cbiAgfVxuXG4gIC8vIExvb2sgdXAgbG9naWNhbCBJRCBmcm9tIGRpc3RyaWJ1dGlvbiBJRCwgdmVyaWZ5IGFnYWluc3Qgb3VyIHN0YWNrIElEXG4gIGNvbnN0IGRpc3RMb2dpY2FsSWQgPSBhd2FpdCBsb29rdXBEaXN0cmlidXRpb25Mb2dpY2FsSWRGcm9tQXJuKGRpc3QsIGV2ZW50LlN0YWNrSWQpO1xuICBpZiAoIWRpc3RMb2dpY2FsSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3VuYWJsZSB0byBsb2NhdGUgZGlzdHJpYnV0aW9uIGluIHN0YWNrJyk7XG4gIH1cblxuICAvLyBOT1RFOiBUaGlzIGxvZ2ljIG11c3QgYmUgZHVwbGljYXRlZCBleGFjdGx5IGZyb20gY29tcHV0ZVNhZmV0eUNoZWNrVGFnTmFtZVxuICBjb25zdCBzYWZldHlDaGVja1RleHQgPSBwcm9jZXNzLmVudi5DREtfU1RBQ0tfTkFNRSArICd8JyArIGRpc3RMb2dpY2FsSWQ7XG4gIGNvbnN0IHNhZmV0eUNoZWNrSGFzaCA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShzYWZldHlDaGVja1RleHQpLmRpZ2VzdCgnaGV4Jykuc2xpY2UoLTMyKTtcbiAgY29uc3QgdGFnTmFtZVJPID0gYGF3cy1jZGs6Z3JhbnQtZGlzdHJpYnV0aW9uLXJvOiR7c2FmZXR5Q2hlY2tIYXNofWA7XG4gIGNvbnN0IHRhZ05hbWVSVyA9IGBhd3MtY2RrOmdyYW50LWRpc3RyaWJ1dGlvbi1ydzoke3NhZmV0eUNoZWNrSGFzaH1gO1xuXG4gIGNvbnN0IGRlZHVwZVNldCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBoYXNOZXZlclNlZW4gPSAoZTogc3RyaW5nKSA9PiAhZGVkdXBlU2V0LmhhcyhlKSAmJiAhIWRlZHVwZVNldC5hZGQoZSk7XG4gIC8vIFByb2Nlc3MgYXJuc1JXIGZpcnN0IGluIGNhc2UgYW4gQVJOIGFwcGVhcnMgaW4gYm90aCBhcm5zUlcgYW5kIGFybnNST1xuICBjb25zdCBkZWR1cGVkUlcgPSBhcm5zUlcuZmlsdGVyKGhhc05ldmVyU2Vlbik7XG4gIGNvbnN0IGRlZHVwZWRSTyA9IGFybnNSTy5maWx0ZXIoaGFzTmV2ZXJTZWVuKTtcblxuICBjb25zdCBwb2xpY3lTaWQgPSBnZW5lcmF0ZVBvbGljeVNpZChwaHlzaWNhbElkKTtcbiAgY29uc3QgZGVsZXRlT25seSA9IGV2ZW50LlJlcXVlc3RUeXBlID09PSAnRGVsZXRlJztcbiAgYXdhaXQgcHJvY2Vzc0FybnMocG9saWN5U2lkLCBkaXN0LCBkZWR1cGVkUk8sIGRlZHVwZWRSVywgZGVsZXRlT25seSwgdGFnTmFtZVJPLCB0YWdOYW1lUlcpO1xuXG4gIHJldHVybiB7XG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbElkLFxuICB9O1xufVxuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json index 50b4d13c40618..2253378d292ac 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/integ.json @@ -3,8 +3,7 @@ "testCases": { "CloudFrontS3OriginOACTest/DefaultTest": { "stacks": [ - "s3origin-oac-1", - "s3origin-oac-multistack" + "s3origin-oac" ], "assertionStack": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert", "assertionStackName": "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588" diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json index 77c4fb6775c7f..e9a0d401ef6e5 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/manifest.json @@ -1,27 +1,27 @@ { "version": "31.0.0", "artifacts": { - "s3origin-oac-1.assets": { + "s3origin-oac.assets": { "type": "cdk:asset-manifest", "properties": { - "file": "s3origin-oac-1.assets.json", + "file": "s3origin-oac.assets.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" } }, - "s3origin-oac-1": { + "s3origin-oac": { "type": "aws:cloudformation:stack", "environment": "aws://unknown-account/unknown-region", "properties": { - "templateFile": "s3origin-oac-1.template.json", + "templateFile": "s3origin-oac.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}/975ebefe3e22c5aaee8a2186d6e669e28c4bfc37ea1a312bf0d1041fbcd1de51.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/6a47cde545ead85d9625b0337e93dcf63b8415c304d9500af14d6753ec7b4365.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ - "s3origin-oac-1.assets" + "s3origin-oac.assets" ], "lookupRole": { "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", @@ -30,155 +30,107 @@ } }, "dependencies": [ - "s3origin-oac-1.assets" + "s3origin-oac.assets" ], "metadata": { - "/s3origin-oac-1/Bucket/Resource": [ + "/s3origin-oac/Bucket/Resource": [ { "type": "aws:cdk:logicalId", "data": "Bucket83908E77" } ], - "/s3origin-oac-1/Bucket/Policy/Resource": [ + "/s3origin-oac/Bucket/Policy/Resource": [ { "type": "aws:cdk:logicalId", "data": "BucketPolicyE9A3008A" } ], - "/s3origin-oac-1/Bucket/AutoDeleteObjectsCustomResource/Default": [ + "/s3origin-oac/BucketKMS/Key/Resource": [ { "type": "aws:cdk:logicalId", - "data": "BucketAutoDeleteObjectsCustomResourceBAFD23C2" + "data": "BucketKMSKeyCAB5A69D" } ], - "/s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + "/s3origin-oac/BucketKMS/Resource": [ { "type": "aws:cdk:logicalId", - "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + "data": "BucketKMS6F50E1CE" } ], - "/s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + "/s3origin-oac/BucketKMS/Policy/Resource": [ { "type": "aws:cdk:logicalId", - "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + "data": "BucketKMSPolicy86072B94" } ], - "/s3origin-oac-1/OACNeverSign/Resource": [ + "/s3origin-oac/OACNeverSign/Resource": [ { "type": "aws:cdk:logicalId", "data": "OACNeverSign93357AE1" } ], - "/s3origin-oac-1/DistDefault/Resource": [ + "/s3origin-oac/Dist/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DistDefaultFA5D01D0" + "data": "DistB3B78991" } ], - "/s3origin-oac-1/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource": [ + "/s3origin-oac/Dist/PolicySetter1/CustomResource/Default": [ { "type": "aws:cdk:logicalId", - "data": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" - } - ], - "/s3origin-oac-1/DistNoPolicy/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "DistNoPolicyC5896EBB" - } - ], - "/s3origin-oac-1/DistRWPolicy/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "DistRWPolicy5EAF946C" + "data": "DistPolicySetter1CustomResourceD490063B" } ], - "/s3origin-oac-1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}": [ + "/s3origin-oac/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" + "data": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" } ], - "/s3origin-oac-1/Exports/Output{\"Ref\":\"Bucket83908E77\"}": [ + "/s3origin-oac/PolicySetterRoleBE2A9A12670B7315BEB492754791DF75/Role": [ { "type": "aws:cdk:logicalId", - "data": "ExportsOutputRefBucket83908E7781C90AC0" + "data": "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75Role57985506" } ], - "/s3origin-oac-1/BootstrapVersion": [ + "/s3origin-oac/PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProvider/Handler": [ { "type": "aws:cdk:logicalId", - "data": "BootstrapVersion" + "data": "PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProviderHandler0EE1A04C" } ], - "/s3origin-oac-1/CheckBootstrapVersion": [ + "/s3origin-oac/DistNoPolicy/Resource": [ { "type": "aws:cdk:logicalId", - "data": "CheckBootstrapVersion" + "data": "DistNoPolicyC5896EBB" } - ] - }, - "displayName": "s3origin-oac-1" - }, - "s3origin-oac-multistack.assets": { - "type": "cdk:asset-manifest", - "properties": { - "file": "s3origin-oac-multistack.assets.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" - } - }, - "s3origin-oac-multistack": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "s3origin-oac-multistack.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}/a67e710f43b68ae6f010f859dec3c563f3637bb9ea3a9ffc40af3a93c5ab360e.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", - "additionalDependencies": [ - "s3origin-oac-multistack.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": [ - "s3origin-oac-1", - "s3origin-oac-multistack.assets" - ], - "metadata": { - "/s3origin-oac-multistack/DistCrossStack/Resource": [ + "/s3origin-oac/DistRWPolicy/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DistCrossStackDEBC5038" + "data": "DistRWPolicy5EAF946C" } ], - "/s3origin-oac-multistack/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource": [ + "/s3origin-oac/DistRWPolicy/PolicySetter1/CustomResource/Default": [ { "type": "aws:cdk:logicalId", - "data": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + "data": "DistRWPolicyPolicySetter1CustomResource3C6A1236" } ], - "/s3origin-oac-multistack/BootstrapVersion": [ + "/s3origin-oac/BootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "BootstrapVersion" } ], - "/s3origin-oac-multistack/CheckBootstrapVersion": [ + "/s3origin-oac/CheckBootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } ] }, - "displayName": "s3origin-oac-multistack" + "displayName": "s3origin-oac" }, "CloudFrontS3OriginOACTestDefaultTestDeployAssert62DBC588.assets": { "type": "cdk:asset-manifest", diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json deleted file mode 100644 index 09e27a21af9ad..0000000000000 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-multistack.template.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "Resources": { - "DistCrossStackDEBC5038": { - "Type": "AWS::CloudFront::Distribution", - "Properties": { - "DistributionConfig": { - "CacheBehaviors": [ - { - "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", - "Compress": true, - "PathPattern": "0/*", - "TargetOriginId": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", - "ViewerProtocolPolicy": "allow-all" - } - ], - "DefaultCacheBehavior": { - "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", - "Compress": true, - "TargetOriginId": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", - "ViewerProtocolPolicy": "allow-all" - }, - "Enabled": true, - "HttpVersion": "http2", - "IPV6Enabled": true, - "Origins": [ - { - "DomainName": { - "Fn::ImportValue": "s3origin-oac-1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" - }, - "Id": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", - "OriginAccessControlId": { - "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" - }, - "S3OriginConfig": {} - }, - { - "DomainName": { - "Fn::Join": [ - "", - [ - { - "Fn::ImportValue": "s3origin-oac-1:ExportsOutputRefBucket83908E7781C90AC0" - }, - ".s3.", - { - "Ref": "AWS::Region" - }, - ".", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - }, - "Id": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", - "OriginAccessControlId": { - "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" - }, - "S3OriginConfig": {} - } - ] - } - } - }, - "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28": { - "Type": "AWS::CloudFront::OriginAccessControl", - "Properties": { - "OriginAccessControlConfig": { - "Name": "s3originoacmultistackOriginAEFE0CA7DB170D0C7D8E8DC4943CF8E9591F8", - "OriginAccessControlOriginType": "s3", - "SigningBehavior": "always", - "SigningProtocol": "sigv4" - } - } - } - }, - "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-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac.assets.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac.assets.json new file mode 100644 index 0000000000000..897c49420b751 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac.assets.json @@ -0,0 +1,32 @@ +{ + "version": "31.0.0", + "files": { + "4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b": { + "source": { + "path": "asset.4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "6a47cde545ead85d9625b0337e93dcf63b8415c304d9500af14d6753ec7b4365": { + "source": { + "path": "s3origin-oac.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6a47cde545ead85d9625b0337e93dcf63b8415c304d9500af14d6753ec7b4365.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-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.template.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac.template.json similarity index 62% rename from packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.template.json rename to packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac.template.json index afd00ebfe6841..b136e9312a5d2 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac-1.template.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/s3origin-oac.template.json @@ -2,14 +2,6 @@ "Resources": { "Bucket83908E77": { "Type": "AWS::S3::Bucket", - "Properties": { - "Tags": [ - { - "Key": "aws-cdk:auto-delete-objects", - "Value": "true" - } - ] - }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -22,45 +14,54 @@ "PolicyDocument": { "Statement": [ { - "Action": [ - "s3:DeleteObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistB3B78991" + } + ] + ] + } + } + }, "Effect": "Allow", "Principal": { - "AWS": { - "Fn::GetAtt": [ - "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", - "Arn" - ] - } + "Service": "cloudfront.amazonaws.com" }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - } - ] + ] + } }, { - "Action": "s3:GetObject", + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], "Condition": { "StringEquals": { "aws:SourceArn": { @@ -77,7 +78,7 @@ }, ":distribution/", { - "Ref": "DistDefaultFA5D01D0" + "Ref": "DistRWPolicy5EAF946C" } ] ] @@ -102,12 +103,111 @@ ] ] } + } + ], + "Version": "2012-10-17" + } + } + }, + "BucketKMSKeyCAB5A69D": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" }, { "Action": [ - "s3:GetObject", - "s3:PutObject" + "kms:GetKeyPolicy", + "kms:ListResourceTags", + "kms:PutKeyPolicy" ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75Role57985506", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "Description": "Created by s3origin-oac/BucketKMS", + "Tags": [ + { + "Key": "aws-cdk:grant-distribution-ro:b5db32fd5b0c29d4f5d29e99c225cace", + "Value": "1" + }, + { + "Key": "aws-cdk:grant-distribution-ro:5e8c3a1685d906af0ac685a3a4d2ef23", + "Value": "1" + }, + { + "Key": "aws-cdk:allow-policy-setter:be2a9a12670b7315beb492754791df75", + "Value": "1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketKMS6F50E1CE": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { + "Fn::GetAtt": [ + "BucketKMSKeyCAB5A69D", + "Arn" + ] + }, + "SSEAlgorithm": "aws:kms" + } + } + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketKMSPolicy86072B94": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "BucketKMS6F50E1CE" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:GetObject", "Condition": { "StringEquals": { "aws:SourceArn": { @@ -124,7 +224,7 @@ }, ":distribution/", { - "Ref": "DistRWPolicy5EAF946C" + "Ref": "DistB3B78991" } ] ] @@ -141,7 +241,7 @@ [ { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "Arn" ] }, @@ -185,7 +285,7 @@ [ { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "Arn" ] }, @@ -199,95 +299,18 @@ } } }, - "BucketAutoDeleteObjectsCustomResourceBAFD23C2": { - "Type": "Custom::S3AutoDeleteObjects", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", - "Arn" - ] - }, - "BucketName": { - "Ref": "Bucket83908E77" - } - }, - "DependsOn": [ - "BucketPolicyE9A3008A" - ], - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, - "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - } - ] - }, - "ManagedPolicyArns": [ - { - "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - } - ] - } - }, - "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "S3Bucket": { - "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" - }, - "S3Key": "40aa87cdf43c4095cec18bc443965f22ab2f8c1ace47e482a0ba4e35d83b0cc9.zip" - }, - "Timeout": 900, - "MemorySize": 128, - "Handler": "__entrypoint__.handler", - "Role": { - "Fn::GetAtt": [ - "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", - "Arn" - ] - }, - "Runtime": "nodejs14.x", - "Description": { - "Fn::Join": [ - "", - [ - "Lambda function for auto-deleting objects in ", - { - "Ref": "Bucket83908E77" - }, - " S3 bucket." - ] - ] - } - }, - "DependsOn": [ - "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" - ] - }, "OACNeverSign93357AE1": { "Type": "AWS::CloudFront::OriginAccessControl", "Properties": { "OriginAccessControlConfig": { - "Name": "s3originoac1OACNeverSign149329B5", + "Name": "s3originoacOACNeverSignDCFC8EEA", "OriginAccessControlOriginType": "s3", "SigningBehavior": "never", "SigningProtocol": "sigv4" } } }, - "DistDefaultFA5D01D0": { + "DistB3B78991": { "Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { @@ -296,28 +319,21 @@ "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, "PathPattern": "0/*", - "TargetOriginId": "s3originoac1DistDefaultOrigin29F927ED7", + "TargetOriginId": "s3originoacDistOrigin24C0EB751", "ViewerProtocolPolicy": "allow-all" }, { "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, "PathPattern": "1/*", - "TargetOriginId": "s3originoac1DistDefaultOrigin32A302443", - "ViewerProtocolPolicy": "allow-all" - }, - { - "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", - "Compress": true, - "PathPattern": "2/*", - "TargetOriginId": "s3originoac1DistDefaultOrigin428E3D9E3", + "TargetOriginId": "s3originoacDistOrigin393D6A56D", "ViewerProtocolPolicy": "allow-all" } ], "DefaultCacheBehavior": { "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, - "TargetOriginId": "s3originoac1DistDefaultOrigin1EAFF2C45", + "TargetOriginId": "s3originoacDistOrigin1FDA0F11F", "ViewerProtocolPolicy": "allow-all" }, "Enabled": true, @@ -331,7 +347,7 @@ "RegionalDomainName" ] }, - "Id": "s3originoac1DistDefaultOrigin1EAFF2C45", + "Id": "s3originoacDistOrigin1FDA0F11F", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, @@ -344,53 +360,168 @@ "RegionalDomainName" ] }, - "Id": "s3originoac1DistDefaultOrigin29F927ED7", + "Id": "s3originoacDistOrigin24C0EB751", "OriginAccessControlId": { - "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + "Ref": "OACNeverSign93357AE1" }, "S3OriginConfig": {} }, { "DomainName": { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "RegionalDomainName" ] }, - "Id": "s3originoac1DistDefaultOrigin32A302443", + "Id": "s3originoacDistOrigin393D6A56D", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, "S3OriginConfig": {} - }, - { - "DomainName": { - "Fn::GetAtt": [ - "Bucket83908E77", - "RegionalDomainName" - ] - }, - "Id": "s3originoac1DistDefaultOrigin428E3D9E3", - "OriginAccessControlId": { - "Ref": "OACNeverSign93357AE1" - }, - "S3OriginConfig": {} } ] } } }, + "DistPolicySetter1CustomResourceD490063B": { + "Type": "Custom::CDKCloudFrontDistributionPolicySetter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProviderHandler0EE1A04C", + "Arn" + ] + }, + "distribution": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistB3B78991" + } + ] + ] + }, + "readOnlyArns": [ + { + "Fn::GetAtt": [ + "BucketKMSKeyCAB5A69D", + "Arn" + ] + } + ], + "readWriteArns": [] + }, + "DependsOn": [ + "BucketKMSKeyCAB5A69D" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28": { "Type": "AWS::CloudFront::OriginAccessControl", "Properties": { "OriginAccessControlConfig": { - "Name": "s3originoac1OriginAccessContEFE0CA7DB170D0C7D8E8DC4943CF08146470", + "Name": "s3originoacOriginAccessContrEFE0CA7DB170D0C7D8E8DC4943CF2076AF28", "OriginAccessControlOriginType": "s3", "SigningBehavior": "always", "SigningProtocol": "sigv4" } } }, + "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75Role57985506": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "kms:GetKeyPolicy", + "kms:PutKeyPolicy", + "kms:ListResourceTags", + "s3:GetBucketPolicy", + "s3:PutBucketPolicy", + "s3:GetBucketTagging" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/aws-cdk:allow-policy-setter:be2a9a12670b7315beb492754791df75": "1" + } + } + }, + { + "Effect": "Allow", + "Action": "cloudformation:DescribeStackResources", + "Resource": "*" + } + ] + } + } + ] + } + }, + "PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProviderHandler0EE1A04C": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "4485729abbaa35138967aa41107932ee600a9d6b27a560e0dfeb9ced4595903b.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75Role57985506", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Environment": { + "Variables": { + "AWS_STS_REGIONAL_ENDPOINTS": "regional", + "CDK_STACK_NAME": "s3origin-oac" + } + } + }, + "DependsOn": [ + "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75Role57985506" + ] + }, "DistNoPolicyC5896EBB": { "Type": "AWS::CloudFront::Distribution", "Properties": { @@ -400,28 +531,28 @@ "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, "PathPattern": "0/*", - "TargetOriginId": "s3originoac1DistNoPolicyOrigin21D41D317", + "TargetOriginId": "s3originoacDistNoPolicyOrigin2CFC99924", "ViewerProtocolPolicy": "allow-all" }, { "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, "PathPattern": "1/*", - "TargetOriginId": "s3originoac1DistNoPolicyOrigin37FFA8314", + "TargetOriginId": "s3originoacDistNoPolicyOrigin3E11E2BE9", "ViewerProtocolPolicy": "allow-all" }, { "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, "PathPattern": "2/*", - "TargetOriginId": "s3originoac1DistNoPolicyOrigin4E5B59189", + "TargetOriginId": "s3originoacDistNoPolicyOrigin4A23B73F9", "ViewerProtocolPolicy": "allow-all" } ], "DefaultCacheBehavior": { "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, - "TargetOriginId": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "TargetOriginId": "s3originoacDistNoPolicyOrigin1D1D9199A", "ViewerProtocolPolicy": "allow-all" }, "Enabled": true, @@ -435,7 +566,7 @@ "RegionalDomainName" ] }, - "Id": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "Id": "s3originoacDistNoPolicyOrigin1D1D9199A", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, @@ -444,11 +575,11 @@ { "DomainName": { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "RegionalDomainName" ] }, - "Id": "s3originoac1DistNoPolicyOrigin21D41D317", + "Id": "s3originoacDistNoPolicyOrigin2CFC99924", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, @@ -470,7 +601,7 @@ ] ] }, - "Id": "s3originoac1DistNoPolicyOrigin37FFA8314", + "Id": "s3originoacDistNoPolicyOrigin3E11E2BE9", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, @@ -495,7 +626,7 @@ ] ] }, - "Id": "s3originoac1DistNoPolicyOrigin4E5B59189", + "Id": "s3originoacDistNoPolicyOrigin4A23B73F9", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, @@ -514,14 +645,14 @@ "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, "PathPattern": "0/*", - "TargetOriginId": "s3originoac1DistRWPolicyOrigin27A3089D1", + "TargetOriginId": "s3originoacDistRWPolicyOrigin22279FB7E", "ViewerProtocolPolicy": "allow-all" } ], "DefaultCacheBehavior": { "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "Compress": true, - "TargetOriginId": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "TargetOriginId": "s3originoacDistRWPolicyOrigin179B95CE8", "ViewerProtocolPolicy": "allow-all" }, "Enabled": true, @@ -535,7 +666,7 @@ "RegionalDomainName" ] }, - "Id": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "Id": "s3originoacDistRWPolicyOrigin179B95CE8", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, @@ -544,11 +675,11 @@ { "DomainName": { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "RegionalDomainName" ] }, - "Id": "s3originoac1DistRWPolicyOrigin27A3089D1", + "Id": "s3originoacDistRWPolicyOrigin22279FB7E", "OriginAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" }, @@ -557,27 +688,50 @@ ] } } - } - }, - "Outputs": { - "ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631": { - "Value": { - "Fn::GetAtt": [ - "Bucket83908E77", - "RegionalDomainName" - ] - }, - "Export": { - "Name": "s3origin-oac-1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" - } }, - "ExportsOutputRefBucket83908E7781C90AC0": { - "Value": { - "Ref": "Bucket83908E77" + "DistRWPolicyPolicySetter1CustomResource3C6A1236": { + "Type": "Custom::CDKCloudFrontDistributionPolicySetter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProviderHandler0EE1A04C", + "Arn" + ] + }, + "distribution": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistRWPolicy5EAF946C" + } + ] + ] + }, + "readOnlyArns": [ + { + "Fn::GetAtt": [ + "BucketKMSKeyCAB5A69D", + "Arn" + ] + } + ], + "readWriteArns": [] }, - "Export": { - "Name": "s3origin-oac-1:ExportsOutputRefBucket83908E7781C90AC0" - } + "DependsOn": [ + "BucketKMSKeyCAB5A69D" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/tree.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/tree.json index 4cd04ac756bc6..1cf7434ad4d0e 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.js.snapshot/tree.json @@ -4,27 +4,20 @@ "id": "App", "path": "", "children": { - "s3origin-oac-1": { - "id": "s3origin-oac-1", - "path": "s3origin-oac-1", + "s3origin-oac": { + "id": "s3origin-oac", + "path": "s3origin-oac", "children": { "Bucket": { "id": "Bucket", - "path": "s3origin-oac-1/Bucket", + "path": "s3origin-oac/Bucket", "children": { "Resource": { "id": "Resource", - "path": "s3origin-oac-1/Bucket/Resource", + "path": "s3origin-oac/Bucket/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::S3::Bucket", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "aws-cdk:auto-delete-objects", - "value": "true" - } - ] - } + "aws:cdk:cloudformation:props": {} }, "constructInfo": { "fqn": "@aws-cdk/aws-s3.CfnBucket", @@ -33,11 +26,11 @@ }, "Policy": { "id": "Policy", - "path": "s3origin-oac-1/Bucket/Policy", + "path": "s3origin-oac/Bucket/Policy", "children": { "Resource": { "id": "Resource", - "path": "s3origin-oac-1/Bucket/Policy/Resource", + "path": "s3origin-oac/Bucket/Policy/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", "aws:cdk:cloudformation:props": { @@ -47,45 +40,54 @@ "policyDocument": { "Statement": [ { - "Action": [ - "s3:DeleteObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", + "Condition": { + "StringEquals": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":cloudfront::", + { + "Ref": "AWS::AccountId" + }, + ":distribution/", + { + "Ref": "DistB3B78991" + } + ] + ] + } + } + }, "Effect": "Allow", "Principal": { - "AWS": { - "Fn::GetAtt": [ - "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", - "Arn" - ] - } + "Service": "cloudfront.amazonaws.com" }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - } - ] + ] + } }, { - "Action": "s3:GetObject", + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], "Condition": { "StringEquals": { "aws:SourceArn": { @@ -102,7 +104,7 @@ }, ":distribution/", { - "Ref": "DistDefaultFA5D01D0" + "Ref": "DistRWPolicy5EAF946C" } ] ] @@ -127,12 +129,177 @@ ] ] } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "BucketHardcoded": { + "id": "BucketHardcoded", + "path": "s3origin-oac/BucketHardcoded", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + }, + "BucketImported": { + "id": "BucketImported", + "path": "s3origin-oac/BucketImported", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + }, + "BucketKMS": { + "id": "BucketKMS", + "path": "s3origin-oac/BucketKMS", + "children": { + "Key": { + "id": "Key", + "path": "s3origin-oac/BucketKMS/Key", + "children": { + "Resource": { + "id": "Resource", + "path": "s3origin-oac/BucketKMS/Key/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" }, { "Action": [ - "s3:GetObject", - "s3:PutObject" + "kms:GetKeyPolicy", + "kms:ListResourceTags", + "kms:PutKeyPolicy" ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75Role57985506", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "description": "Created by s3origin-oac/BucketKMS", + "tags": [ + { + "key": "aws-cdk:grant-distribution-ro:b5db32fd5b0c29d4f5d29e99c225cace", + "value": "1" + }, + { + "key": "aws-cdk:grant-distribution-ro:5e8c3a1685d906af0ac685a3a4d2ef23", + "value": "1" + }, + { + "key": "aws-cdk:allow-policy-setter:be2a9a12670b7315beb492754791df75", + "value": "1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.CfnKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.Key", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "s3origin-oac/BucketKMS/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "aws:kms", + "kmsMasterKeyId": { + "Fn::GetAtt": [ + "BucketKMSKeyCAB5A69D", + "Arn" + ] + } + } + } + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "s3origin-oac/BucketKMS/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "s3origin-oac/BucketKMS/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "BucketKMS6F50E1CE" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:GetObject", "Condition": { "StringEquals": { "aws:SourceArn": { @@ -149,7 +316,7 @@ }, ":distribution/", { - "Ref": "DistRWPolicy5EAF946C" + "Ref": "DistB3B78991" } ] ] @@ -166,7 +333,7 @@ [ { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "Arn" ] }, @@ -210,7 +377,7 @@ [ { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "Arn" ] }, @@ -234,24 +401,6 @@ "fqn": "@aws-cdk/aws-s3.BucketPolicy", "version": "0.0.0" } - }, - "AutoDeleteObjectsCustomResource": { - "id": "AutoDeleteObjectsCustomResource", - "path": "s3origin-oac-1/Bucket/AutoDeleteObjectsCustomResource", - "children": { - "Default": { - "id": "Default", - "path": "s3origin-oac-1/Bucket/AutoDeleteObjectsCustomResource/Default", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } } }, "constructInfo": { @@ -259,68 +408,18 @@ "version": "0.0.0" } }, - "Custom::S3AutoDeleteObjectsCustomResourceProvider": { - "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", - "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider", - "children": { - "Staging": { - "id": "Staging", - "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - }, - "Role": { - "id": "Role", - "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - }, - "Handler": { - "id": "Handler", - "path": "s3origin-oac-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - }, - "BucketHardcoded": { - "id": "BucketHardcoded", - "path": "s3origin-oac-1/BucketHardcoded", - "constructInfo": { - "fqn": "@aws-cdk/aws-s3.BucketBase", - "version": "0.0.0" - } - }, - "BucketImported": { - "id": "BucketImported", - "path": "s3origin-oac-1/BucketImported", - "constructInfo": { - "fqn": "@aws-cdk/aws-s3.BucketBase", - "version": "0.0.0" - } - }, "OACNeverSign": { "id": "OACNeverSign", - "path": "s3origin-oac-1/OACNeverSign", + "path": "s3origin-oac/OACNeverSign", "children": { "Resource": { "id": "Resource", - "path": "s3origin-oac-1/OACNeverSign/Resource", + "path": "s3origin-oac/OACNeverSign/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", "aws:cdk:cloudformation:props": { "originAccessControlConfig": { - "name": "s3originoac1OACNeverSign149329B5", + "name": "s3originoacOACNeverSignDCFC8EEA", "originAccessControlOriginType": "s3", "signingBehavior": "never", "signingProtocol": "sigv4" @@ -338,13 +437,13 @@ "version": "0.0.0" } }, - "DistDefault": { - "id": "DistDefault", - "path": "s3origin-oac-1/DistDefault", + "Dist": { + "id": "Dist", + "path": "s3origin-oac/Dist", "children": { "Origin1": { "id": "Origin1", - "path": "s3origin-oac-1/DistDefault/Origin1", + "path": "s3origin-oac/Dist/Origin1", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -352,7 +451,7 @@ }, "Resource": { "id": "Resource", - "path": "s3origin-oac-1/DistDefault/Resource", + "path": "s3origin-oac/Dist/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", "aws:cdk:cloudformation:props": { @@ -366,7 +465,7 @@ "RegionalDomainName" ] }, - "id": "s3originoac1DistDefaultOrigin1EAFF2C45", + "id": "s3originoacDistOrigin1FDA0F11F", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" @@ -379,42 +478,29 @@ "RegionalDomainName" ] }, - "id": "s3originoac1DistDefaultOrigin29F927ED7", + "id": "s3originoacDistOrigin24C0EB751", "s3OriginConfig": {}, "originAccessControlId": { - "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" + "Ref": "OACNeverSign93357AE1" } }, { "domainName": { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "RegionalDomainName" ] }, - "id": "s3originoac1DistDefaultOrigin32A302443", + "id": "s3originoacDistOrigin393D6A56D", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" } - }, - { - "domainName": { - "Fn::GetAtt": [ - "Bucket83908E77", - "RegionalDomainName" - ] - }, - "id": "s3originoac1DistDefaultOrigin428E3D9E3", - "s3OriginConfig": {}, - "originAccessControlId": { - "Ref": "OACNeverSign93357AE1" - } } ], "defaultCacheBehavior": { "pathPattern": "*", - "targetOriginId": "s3originoac1DistDefaultOrigin1EAFF2C45", + "targetOriginId": "s3originoacDistOrigin1FDA0F11F", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" @@ -422,21 +508,14 @@ "cacheBehaviors": [ { "pathPattern": "0/*", - "targetOriginId": "s3originoac1DistDefaultOrigin29F927ED7", + "targetOriginId": "s3originoacDistOrigin24C0EB751", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" }, { "pathPattern": "1/*", - "targetOriginId": "s3originoac1DistDefaultOrigin32A302443", - "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", - "compress": true, - "viewerProtocolPolicy": "allow-all" - }, - { - "pathPattern": "2/*", - "targetOriginId": "s3originoac1DistDefaultOrigin428E3D9E3", + "targetOriginId": "s3originoacDistOrigin393D6A56D", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" @@ -454,7 +533,7 @@ }, "Origin2": { "id": "Origin2", - "path": "s3origin-oac-1/DistDefault/Origin2", + "path": "s3origin-oac/Dist/Origin2", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -462,15 +541,35 @@ }, "Origin3": { "id": "Origin3", - "path": "s3origin-oac-1/DistDefault/Origin3", + "path": "s3origin-oac/Dist/Origin3", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" } }, - "Origin4": { - "id": "Origin4", - "path": "s3origin-oac-1/DistDefault/Origin4", + "PolicySetter1": { + "id": "PolicySetter1", + "path": "s3origin-oac/Dist/PolicySetter1", + "children": { + "CustomResource": { + "id": "CustomResource", + "path": "s3origin-oac/Dist/PolicySetter1/CustomResource", + "children": { + "Default": { + "id": "Default", + "path": "s3origin-oac/Dist/PolicySetter1/CustomResource/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + } + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -484,16 +583,16 @@ }, "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF": { "id": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", - "path": "s3origin-oac-1/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", + "path": "s3origin-oac/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", "children": { "Resource": { "id": "Resource", - "path": "s3origin-oac-1/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource", + "path": "s3origin-oac/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", "aws:cdk:cloudformation:props": { "originAccessControlConfig": { - "name": "s3originoac1OriginAccessContEFE0CA7DB170D0C7D8E8DC4943CF08146470", + "name": "s3originoacOriginAccessContrEFE0CA7DB170D0C7D8E8DC4943CF2076AF28", "originAccessControlOriginType": "s3", "signingBehavior": "always", "signingProtocol": "sigv4" @@ -511,13 +610,57 @@ "version": "0.0.0" } }, + "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75": { + "id": "PolicySetterRoleBE2A9A12670B7315BEB492754791DF75", + "path": "s3origin-oac/PolicySetterRoleBE2A9A12670B7315BEB492754791DF75", + "children": { + "Role": { + "id": "Role", + "path": "s3origin-oac/PolicySetterRoleBE2A9A12670B7315BEB492754791DF75/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProvider": { + "id": "PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProvider", + "path": "s3origin-oac/PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "s3origin-oac/PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProvider/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "s3origin-oac/PolicySetterProviderBE2A9A12670B7315BEB492754791DF75CustomResourceProvider/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResourceProvider", + "version": "0.0.0" + } + }, "DistNoPolicy": { "id": "DistNoPolicy", - "path": "s3origin-oac-1/DistNoPolicy", + "path": "s3origin-oac/DistNoPolicy", "children": { "Origin1": { "id": "Origin1", - "path": "s3origin-oac-1/DistNoPolicy/Origin1", + "path": "s3origin-oac/DistNoPolicy/Origin1", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -525,7 +668,7 @@ }, "Resource": { "id": "Resource", - "path": "s3origin-oac-1/DistNoPolicy/Resource", + "path": "s3origin-oac/DistNoPolicy/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", "aws:cdk:cloudformation:props": { @@ -539,7 +682,7 @@ "RegionalDomainName" ] }, - "id": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "id": "s3originoacDistNoPolicyOrigin1D1D9199A", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" @@ -548,11 +691,11 @@ { "domainName": { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "RegionalDomainName" ] }, - "id": "s3originoac1DistNoPolicyOrigin21D41D317", + "id": "s3originoacDistNoPolicyOrigin2CFC99924", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" @@ -574,7 +717,7 @@ ] ] }, - "id": "s3originoac1DistNoPolicyOrigin37FFA8314", + "id": "s3originoacDistNoPolicyOrigin3E11E2BE9", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" @@ -599,7 +742,7 @@ ] ] }, - "id": "s3originoac1DistNoPolicyOrigin4E5B59189", + "id": "s3originoacDistNoPolicyOrigin4A23B73F9", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" @@ -608,7 +751,7 @@ ], "defaultCacheBehavior": { "pathPattern": "*", - "targetOriginId": "s3originoac1DistNoPolicyOrigin140F4B9A7", + "targetOriginId": "s3originoacDistNoPolicyOrigin1D1D9199A", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" @@ -616,21 +759,21 @@ "cacheBehaviors": [ { "pathPattern": "0/*", - "targetOriginId": "s3originoac1DistNoPolicyOrigin21D41D317", + "targetOriginId": "s3originoacDistNoPolicyOrigin2CFC99924", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" }, { "pathPattern": "1/*", - "targetOriginId": "s3originoac1DistNoPolicyOrigin37FFA8314", + "targetOriginId": "s3originoacDistNoPolicyOrigin3E11E2BE9", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" }, { "pathPattern": "2/*", - "targetOriginId": "s3originoac1DistNoPolicyOrigin4E5B59189", + "targetOriginId": "s3originoacDistNoPolicyOrigin4A23B73F9", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" @@ -648,7 +791,7 @@ }, "Origin2": { "id": "Origin2", - "path": "s3origin-oac-1/DistNoPolicy/Origin2", + "path": "s3origin-oac/DistNoPolicy/Origin2", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -656,7 +799,7 @@ }, "Origin3": { "id": "Origin3", - "path": "s3origin-oac-1/DistNoPolicy/Origin3", + "path": "s3origin-oac/DistNoPolicy/Origin3", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -664,7 +807,7 @@ }, "Origin4": { "id": "Origin4", - "path": "s3origin-oac-1/DistNoPolicy/Origin4", + "path": "s3origin-oac/DistNoPolicy/Origin4", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -678,11 +821,11 @@ }, "DistRWPolicy": { "id": "DistRWPolicy", - "path": "s3origin-oac-1/DistRWPolicy", + "path": "s3origin-oac/DistRWPolicy", "children": { "Origin1": { "id": "Origin1", - "path": "s3origin-oac-1/DistRWPolicy/Origin1", + "path": "s3origin-oac/DistRWPolicy/Origin1", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -690,7 +833,7 @@ }, "Resource": { "id": "Resource", - "path": "s3origin-oac-1/DistRWPolicy/Resource", + "path": "s3origin-oac/DistRWPolicy/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", "aws:cdk:cloudformation:props": { @@ -704,7 +847,7 @@ "RegionalDomainName" ] }, - "id": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "id": "s3originoacDistRWPolicyOrigin179B95CE8", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" @@ -713,11 +856,11 @@ { "domainName": { "Fn::GetAtt": [ - "Bucket83908E77", + "BucketKMS6F50E1CE", "RegionalDomainName" ] }, - "id": "s3originoac1DistRWPolicyOrigin27A3089D1", + "id": "s3originoacDistRWPolicyOrigin22279FB7E", "s3OriginConfig": {}, "originAccessControlId": { "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" @@ -726,7 +869,7 @@ ], "defaultCacheBehavior": { "pathPattern": "*", - "targetOriginId": "s3originoac1DistRWPolicyOrigin12C2C2C74", + "targetOriginId": "s3originoacDistRWPolicyOrigin179B95CE8", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" @@ -734,7 +877,7 @@ "cacheBehaviors": [ { "pathPattern": "0/*", - "targetOriginId": "s3originoac1DistRWPolicyOrigin27A3089D1", + "targetOriginId": "s3originoacDistRWPolicyOrigin22279FB7E", "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", "compress": true, "viewerProtocolPolicy": "allow-all" @@ -752,156 +895,35 @@ }, "Origin2": { "id": "Origin2", - "path": "s3origin-oac-1/DistRWPolicy/Origin2", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-cloudfront.Distribution", - "version": "0.0.0" - } - }, - "Exports": { - "id": "Exports", - "path": "s3origin-oac-1/Exports", - "children": { - "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}": { - "id": "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}", - "path": "s3origin-oac-1/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"RegionalDomainName\"]}", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - }, - "Output{\"Ref\":\"Bucket83908E77\"}": { - "id": "Output{\"Ref\":\"Bucket83908E77\"}", - "path": "s3origin-oac-1/Exports/Output{\"Ref\":\"Bucket83908E77\"}", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - }, - "BootstrapVersion": { - "id": "BootstrapVersion", - "path": "s3origin-oac-1/BootstrapVersion", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - }, - "CheckBootstrapVersion": { - "id": "CheckBootstrapVersion", - "path": "s3origin-oac-1/CheckBootstrapVersion", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" - } - }, - "s3origin-oac-multistack": { - "id": "s3origin-oac-multistack", - "path": "s3origin-oac-multistack", - "children": { - "DistCrossStack": { - "id": "DistCrossStack", - "path": "s3origin-oac-multistack/DistCrossStack", - "children": { - "Origin1": { - "id": "Origin1", - "path": "s3origin-oac-multistack/DistCrossStack/Origin1", + "path": "s3origin-oac/DistRWPolicy/Origin2", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" } }, - "Resource": { - "id": "Resource", - "path": "s3origin-oac-multistack/DistCrossStack/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::CloudFront::Distribution", - "aws:cdk:cloudformation:props": { - "distributionConfig": { - "enabled": true, - "origins": [ - { - "domainName": { - "Fn::ImportValue": "s3origin-oac-1:ExportsOutputFnGetAttBucket83908E77RegionalDomainName2BE53631" - }, - "id": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", - "s3OriginConfig": {}, - "originAccessControlId": { - "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" - } - }, - { - "domainName": { - "Fn::Join": [ - "", - [ - { - "Fn::ImportValue": "s3origin-oac-1:ExportsOutputRefBucket83908E7781C90AC0" - }, - ".s3.", - { - "Ref": "AWS::Region" - }, - ".", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - }, - "id": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", - "s3OriginConfig": {}, - "originAccessControlId": { - "Ref": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CFAFE70B28" - } - } - ], - "defaultCacheBehavior": { - "pathPattern": "*", - "targetOriginId": "s3originoacmultistackDistCrossStackOrigin1B87A34D7", - "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", - "compress": true, - "viewerProtocolPolicy": "allow-all" - }, - "cacheBehaviors": [ - { - "pathPattern": "0/*", - "targetOriginId": "s3originoacmultistackDistCrossStackOrigin2C0D71C3F", - "cachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", - "compress": true, - "viewerProtocolPolicy": "allow-all" + "PolicySetter1": { + "id": "PolicySetter1", + "path": "s3origin-oac/DistRWPolicy/PolicySetter1", + "children": { + "CustomResource": { + "id": "CustomResource", + "path": "s3origin-oac/DistRWPolicy/PolicySetter1/CustomResource", + "children": { + "Default": { + "id": "Default", + "path": "s3origin-oac/DistRWPolicy/PolicySetter1/CustomResource/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" } - ], - "httpVersion": "http2", - "ipv6Enabled": true + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" } } }, - "constructInfo": { - "fqn": "@aws-cdk/aws-cloudfront.CfnDistribution", - "version": "0.0.0" - } - }, - "Origin2": { - "id": "Origin2", - "path": "s3origin-oac-multistack/DistCrossStack/Origin2", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.270" @@ -913,55 +935,26 @@ "version": "0.0.0" } }, - "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF": { - "id": "OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", - "path": "s3origin-oac-multistack/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF", - "children": { - "Resource": { - "id": "Resource", - "path": "s3origin-oac-multistack/OriginAccessControlACB7EFE0CA7DB170D0C7D8E8DC4943CF/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::CloudFront::OriginAccessControl", - "aws:cdk:cloudformation:props": { - "originAccessControlConfig": { - "name": "s3originoacmultistackOriginAEFE0CA7DB170D0C7D8E8DC4943CF8E9591F8", - "originAccessControlOriginType": "s3", - "signingBehavior": "always", - "signingProtocol": "sigv4" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-cloudfront.CfnOriginAccessControl", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-cloudfront.OriginAccessControl", - "version": "0.0.0" - } - }, "BootstrapVersion": { "id": "BootstrapVersion", - "path": "s3origin-oac-multistack/BootstrapVersion", + "path": "s3origin-oac/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", - "path": "s3origin-oac-multistack/CheckBootstrapVersion", + "path": "s3origin-oac/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" } }, "CloudFrontS3OriginOACTest": { @@ -988,22 +981,22 @@ "id": "BootstrapVersion", "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "CloudFrontS3OriginOACTest/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" } } }, @@ -1028,8 +1021,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts index d7c060dbca6b1..220f2e374660c 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin-oac.ts @@ -4,12 +4,16 @@ import * as cdk from '@aws-cdk/core'; import * as integ from '@aws-cdk/integ-tests'; import * as origins from '../lib'; -class S3OriginOAC extends origins.S3Origin { - constructor(bucket: s3.IBucket, props?: origins.S3OriginProps) { - if (props?.originAccessControl === undefined) { - props = { ...(props ?? {}), originAccessControl: true }; - } - super(bucket, props); +class TestS3OriginOAC extends origins.S3Origin { + constructor( + bucket: s3.IBucket, + policy?: origins.S3OriginAutoResourcePolicy | boolean, + oac?: cloudfront.OriginAccessControl, + ) { + super(bucket, { + autoResourcePolicy: policy, + originAccessControl: oac ?? true, + }); } } @@ -22,46 +26,40 @@ function makeDistribution(stack: cdk.Stack, id: string, first: cloudfront.IOrigi const app = new cdk.App(); -const stack1 = new cdk.Stack(app, 's3origin-oac-1'); -const bucket = new s3.Bucket(stack1, 'Bucket', { - removalPolicy: cdk.RemovalPolicy.DESTROY, - autoDeleteObjects: true, -}); +const stack1 = new cdk.Stack(app, 's3origin-oac'); +const bucket = new s3.Bucket(stack1, 'Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY }); const bucketByName = s3.Bucket.fromBucketName(stack1, 'BucketHardcoded', 's3origin-oac-test-bucket'); const bucketImport = s3.Bucket.fromBucketName(stack1, 'BucketImported', bucket.bucketName); +const bucketWithKMS = new s3.Bucket(stack1, 'BucketKMS', { + encryption: s3.BucketEncryption.KMS, + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); +bucketWithKMS.encryptionKey?.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY); + const oacCustom = new cloudfront.OriginAccessControl(stack1, 'OACNeverSign', { originType: cloudfront.OriginAccessControlOriginType.S3, signingBehavior: cloudfront.OriginAccessControlSigningBehavior.NEVER, }); -makeDistribution(stack1, 'DistDefault', - // this distribution will be granted access to the bucket via resource policy - new S3OriginOAC(bucket), - new S3OriginOAC(bucket, { autoResourcePolicy: true }), // should collapse with above - new S3OriginOAC(bucket, { autoResourcePolicy: false }), // no effect on policy - new S3OriginOAC(bucket, { originAccessControl: oacCustom }), +makeDistribution(stack1, 'Dist', + new TestS3OriginOAC(bucket), + new TestS3OriginOAC(bucket, undefined, oacCustom), + new TestS3OriginOAC(bucketWithKMS), ); + makeDistribution(stack1, 'DistNoPolicy', - // this distribution will not be granted access to any buckets via resource policy - new S3OriginOAC(bucket, { autoResourcePolicy: false }), - new S3OriginOAC(bucket, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.NONE }), - new S3OriginOAC(bucketByName, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.NONE }), - new S3OriginOAC(bucketImport, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.NONE }), -); -makeDistribution(stack1, 'DistRWPolicy', - // this distribution will be granted full read-write access to bucket via resource policy - new S3OriginOAC(bucket, { autoResourcePolicy: origins.S3OriginAutoResourcePolicy.READ_WRITE }), - new S3OriginOAC(bucket, { autoResourcePolicy: true }), // should collapse with above + new TestS3OriginOAC(bucket, false), + new TestS3OriginOAC(bucketWithKMS, false), + new TestS3OriginOAC(bucketByName, origins.S3OriginAutoResourcePolicy.NONE), + new TestS3OriginOAC(bucketImport, origins.S3OriginAutoResourcePolicy.NONE), ); -const stack2 = new cdk.Stack(app, 's3origin-oac-multistack'); -makeDistribution(stack2, 'DistCrossStack', - new S3OriginOAC(bucket, { autoResourcePolicy: false }), - new S3OriginOAC(bucketImport, { autoResourcePolicy: false }), +makeDistribution(stack1, 'DistRWPolicy', + new TestS3OriginOAC(bucket, origins.S3OriginAutoResourcePolicy.READ_WRITE), + new TestS3OriginOAC(bucketWithKMS, true), ); new integ.IntegTest(app, 'CloudFrontS3OriginOACTest', { - testCases: [stack1, stack2], + testCases: [stack1], }); -app.synth();