diff --git a/CHANGELOG.md b/CHANGELOG.md index 27c2b85f6..3027f25a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.56.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.55.0...v2.56.0) (2024-04-24) + +Built on CDK v2.138.0 + +### Features + +* **s3:** constructs factories - create well architected s3 buckets ([#1110](https://github.com/awslabs/aws-solutions-constructs/issues/1110)) ([f561cf6](https://github.com/awslabs/aws-solutions-constructs/commit/f561cf65c377684c0579417b404b33cdc97fa407)) + ## [2.55.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.54.1...v2.55.0) (2024-04-12) Built on CDK v2.135.0 diff --git a/deployment/v2/align-version.js b/deployment/v2/align-version.js index 95ca949e6..fd5b013d5 100755 --- a/deployment/v2/align-version.js +++ b/deployment/v2/align-version.js @@ -10,7 +10,7 @@ const nullVersionMarker = process.argv[2]; const targetSolutionsConstructsVersion = process.argv[3]; // these versions need to be sourced from a config file -const awsCdkLibVersion = '2.135.0'; +const awsCdkLibVersion = '2.138.0'; for (const file of process.argv.splice(4)) { const pkg = JSON.parse(fs.readFileSync(file).toString()); diff --git a/source/lerna.json b/source/lerna.json index a4963e1e4..42f91b460 100644 --- a/source/lerna.json +++ b/source/lerna.json @@ -6,5 +6,5 @@ "./patterns/@aws-solutions-constructs/*" ], "rejectCycles": "true", - "version": "2.55.0" + "version": "2.56.0" } diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.eslintignore b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.eslintignore new file mode 100644 index 000000000..14ecbec04 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.eslintignore @@ -0,0 +1,7 @@ +lib/*.js +test/*.js +test/s3/*.js +*.d.ts +coverage +test/s3/integ.*.js.snapshot/ +test/s3/cdk-integ.out.integ.*.snapshot diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.gitignore b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.gitignore new file mode 100644 index 000000000..c6de60232 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.gitignore @@ -0,0 +1,16 @@ +lib/*.js +test/*.js +test/s3/*.js +*.js.map +*.d.ts +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.npmignore b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.npmignore new file mode 100644 index 000000000..f66791629 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/.npmignore @@ -0,0 +1,21 @@ +# Exclude typescript source and config +*.ts +tsconfig.json +coverage +.nyc_output +*.tgz +*.snk +*.tsbuildinfo + +# Include javascript files and typescript declarations +!*.js +!*.d.ts + +# Exclude jsii outdir +dist + +# Include .jsii +!.jsii + +# Include .jsii +!.jsii \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/README.md b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/README.md new file mode 100755 index 000000000..3d16240c1 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/README.md @@ -0,0 +1,101 @@ +# aws-constructs-factories module + + +--- + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> All classes are under active development and subject to non-backward compatible changes or removal in any +> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. +> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +| **Reference Documentation**:| https://docs.aws.amazon.com/solutions/latest/constructs/| +|:-------------|:-------------| +
+ +| **Language** | **Package** | +|:-------------|-----------------| +|![Python Logo](https://docs.aws.amazon.com/cdk/api/latest/img/python32.png) Python|`aws_solutions_constructs.aws_constructs_factories`| +|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-constructs-factories`| +|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.constructsfactories`| + +## Overview +This AWS Solutions Construct exposes the same code used to create our underlying resources as factories, so clients can create individual resources that are well-architected. + +### S3 Buckets + +Create fully well-architected S3 buckets with as little as one function call. Here is a minimal deployable pattern definition: + +Typescript +``` typescript +import { Construct } from 'constructs'; +import { Stack, StackProps } from 'aws-cdk-lib'; +import { ConstructsFactories } from '@aws-solutions-constructs/aws-constructs-factories'; + +const factories = new ConstructsFactories(this, 'integ-test'); + +factories.s3BucketFactory('test', {}); +``` + +Python +``` python +# TBD +``` + +Java +``` java +// TBD +``` + +## S3BucketFactory Function Signature + +``` typescript +s3BucketFactory(id: string, props: S3BucketFactoryProps): S3BucketFactoryResponse +``` + +## S3BucketFactoryProps + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +|bucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.BucketProps.html)|Optional user provided props to override the default props for the S3 Bucket.| +|logS3AccessLogs?|`boolean`|Whether to turn on Access Logging for the S3 bucket. Creates an S3 bucket with associated storage costs for the logs. Enabling Access Logging is a best practice. default - true| +|loggingBucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.BucketProps.html)|Optional user provided props to override the default props for the S3 Logging Bucket.| + +## S3BucketFactoryResponse + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +|s3Bucket|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html)|The s3.Bucket created by the factory. | +|s3LoggingBucket?|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html)|The s3.Bucket created by the construct as the logging bucket for the primary bucket. If the logS3AccessLogs property is false, this value will be undefined.| + +## Default settings + +Out of the box implementation of the Construct without any override will set the following defaults: + +* An S3 Content Bucket + * AWS managed Server Side Encryption (AES256) + * Lifecycle rule to transition objects to Glacier storage class in 90 days + * Access Logging enabled + * All Public access blocked + * Versioning enabled + * UpdateReplacePolicy is delete + * Deletion policy is delete + * Bucket policy requiring SecureTransport +* An S3 Bucket for Access Logs + * AWS managed Server Side Encryption (AES256) + * All public access blocked + * Versioning enabled + * UpdateReplacePolicy is delete + * Deletion policy is delete + * Bucket policy requiring SecureTransport + * Bucket policy granting PutObject privileges to the S3 logging service, from the content bucket in the content bucket account. + * cfn_nag suppression of access logging finding (not logging access to the access log bucket) + +## Architecture +![Architecture Diagram](architecture.png) + +*** +© Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/architecture.png b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/architecture.png new file mode 100644 index 000000000..716aa5ef2 Binary files /dev/null and b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/architecture.png differ diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/integ.config.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/integ.config.json new file mode 100644 index 000000000..93d8ca4b6 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/integ.config.json @@ -0,0 +1,7 @@ +{ + "parallelRegions": [ + "us-east-1" + ], + "disable-update-workflow": true, + "update-on-failed": false +} diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/lib/index.ts new file mode 100644 index 000000000..ba17a32b0 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/lib/index.ts @@ -0,0 +1,52 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate +import { Construct } from 'constructs'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as defaults from '@aws-solutions-constructs/core'; + +export interface S3BucketFactoryProps { + readonly bucketProps?: s3.BucketProps | any, + readonly logS3AccessLogs?: boolean, + readonly loggingBucketProps?: s3.BucketProps, +} + +// Create a response specifically for the interface to avoid coupling client with internal implementation +export interface S3BucketFactoryResponse { + readonly s3Bucket: s3.Bucket, + readonly s3LoggingBucket?: s3.Bucket, +} + +export class ConstructsFactories extends Construct { + constructor(scope: Construct, id: string) { + super(scope, id); + } + + public s3BucketFactory(id: string, props: S3BucketFactoryProps): S3BucketFactoryResponse { + defaults.CheckS3Props(props); + + const propsArg: defaults.BuildS3BucketProps = props ? { + bucketProps: props.bucketProps, + loggingBucketProps: props.loggingBucketProps, + logS3AccessLogs: props.logS3AccessLogs, + } : {}; + + const buildS3BucketResponse = defaults.buildS3Bucket(this, propsArg, id); + + return { + s3Bucket: buildS3BucketResponse.bucket, + s3LoggingBucket: buildS3BucketResponse.loggingBucket + }; + } +} diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/package.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/package.json new file mode 100644 index 000000000..c98fe6b47 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/package.json @@ -0,0 +1,92 @@ +{ + "name": "@aws-solutions-constructs/aws-constructs-factories", + "version": "0.0.0", + "description": "Factories to allow creation of individual resources", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/awslabs/aws-solutions-constructs.git", + "directory": "source/patterns/@aws-solutions-constructs/aws-constructs-factories" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "scripts": { + "build": "tsc -b .", + "lint": "eslint -c ../eslintrc.yml --ext=.js,.ts . && tslint --project .", + "lint-fix": "eslint -c ../eslintrc.yml --ext=.js,.ts --fix .", + "test": "jest --coverage", + "clean": "tsc -b --clean", + "watch": "tsc -b -w", + "integ": "integ-runner --update-on-failed", + "integ-no-clean": "integ-runner --update-on-failed --no-clean", + "integ-assert": "integ-runner", + "jsii": "jsii", + "jsii-pacmak": "jsii-pacmak", + "build+lint+test": "npm run jsii && npm run lint && npm test && npm run integ-assert", + "snapshot-update": "npm run jsii && npm test -- -u && npm run integ-assert" + }, + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awsconstructs.services.constructsfactories", + "maven": { + "groupId": "software.amazon.awsconstructs", + "artifactId": "constructsfactories" + } + }, + "dotnet": { + "namespace": "Amazon.SolutionsConstructs.AWS.ConstructsFactories", + "packageId": "Amazon.SolutionsConstructs.AWS.ConstructsFactories", + "signAssembly": true, + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-solutions-constructs.aws-constructs-factories", + "module": "aws_solutions_constructs.aws_constructs_factories" + } + } + }, + "dependencies": { + "@aws-cdk/integ-tests-alpha": "0.0.0-alpha.0", + "@aws-solutions-constructs/core": "0.0.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "@types/jest": "^27.4.0", + "@types/node": "^10.3.0", + "aws-cdk-lib": "0.0.0", + "constructs": "^10.0.0" + }, + "jest": { + "moduleFileExtensions": [ + "js" + ], + "coverageReporters": [ + "text", + [ + "lcov", + { + "projectRoot": "../../../../" + } + ] + ] + }, + "peerDependencies": { + "@aws-solutions-constructs/core": "0.0.0", + "aws-cdk-lib": "0.0.0", + "constructs": "^10.0.0" + }, + "keywords": [ + "aws", + "cdk", + "awscdk", + "Constructs Factories", + "AWS Solutions Constructs" + ] +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/asset.6c1e9b465fa4b2d651dbc9ce3e732d8702a7b19137327684a71d89f1d355f1a2/index.js b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/asset.6c1e9b465fa4b2d651dbc9ce3e732d8702a7b19137327684a71d89f1d355f1a2/index.js new file mode 100644 index 000000000..4b04680b8 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/asset.6c1e9b465fa4b2d651dbc9ce3e732d8702a7b19137327684a71d89f1d355f1a2/index.js @@ -0,0 +1 @@ +"use strict";var I=Object.create,i=Object.defineProperty,w=Object.getOwnPropertyDescriptor,P=Object.getOwnPropertyNames,A=Object.getPrototypeOf,L=Object.prototype.hasOwnProperty,k=(e,t)=>{for(var o in t)i(e,o,{get:t[o],enumerable:!0})},d=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of P(t))!L.call(e,s)&&s!==o&&i(e,s,{get:()=>t[s],enumerable:!(n=w(t,s))||n.enumerable});return e},l=(e,t,o)=>(o=e!=null?I(A(e)):{},d(t||!e||!e.__esModule?i(o,"default",{value:e,enumerable:!0}):o,e)),B=e=>d(i({},"__esModule",{value:!0}),e),q={};k(q,{autoDeleteHandler:()=>S,handler:()=>_}),module.exports=B(q);var h=require("@aws-sdk/client-s3"),y=l(require("https")),m=l(require("url")),a={sendHttpRequest:b,log:O,includeStackTraces:!0,userHandlerIndex:"./index"},p="AWSCDK::CustomResourceProviderFramework::CREATE_FAILED",D="AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID";function R(e){return async(t,o)=>{let n={...t,ResponseURL:"..."};if(a.log(JSON.stringify(n,void 0,2)),t.RequestType==="Delete"&&t.PhysicalResourceId===p){a.log("ignoring DELETE event caused by a failed CREATE event"),await u("SUCCESS",t);return}try{let s=await e(n,o),r=T(t,s);await u("SUCCESS",r)}catch(s){let r={...t,Reason:a.includeStackTraces?s.stack:s.message};r.PhysicalResourceId||(t.RequestType==="Create"?(a.log("CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored"),r.PhysicalResourceId=p):a.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(t)}`)),await u("FAILED",r)}}}function T(e,t={}){let o=t.PhysicalResourceId??e.PhysicalResourceId??e.RequestId;if(e.RequestType==="Delete"&&o!==e.PhysicalResourceId)throw new Error(`DELETE: cannot change the physical resource ID from "${e.PhysicalResourceId}" to "${t.PhysicalResourceId}" during deletion`);return{...e,...t,PhysicalResourceId:o}}async function u(e,t){let o={Status:e,Reason:t.Reason??e,StackId:t.StackId,RequestId:t.RequestId,PhysicalResourceId:t.PhysicalResourceId||D,LogicalResourceId:t.LogicalResourceId,NoEcho:t.NoEcho,Data:t.Data},n=m.parse(t.ResponseURL),s=`${n.protocol}//${n.hostname}/${n.pathname}?***`;a.log("submit response to cloudformation",s,o);let r=JSON.stringify(o),C={hostname:n.hostname,path:n.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(r,"utf8")}};await x({attempts:5,sleep:1e3},a.sendHttpRequest)(C,r)}async function b(e,t){return new Promise((o,n)=>{try{let s=y.request(e,r=>{r.resume(),!r.statusCode||r.statusCode>=400?n(new Error(`Unsuccessful HTTP response: ${r.statusCode}`)):o()});s.on("error",n),s.write(t),s.end()}catch(s){n(s)}})}function O(e,...t){console.log(e,...t)}function x(e,t){return async(...o)=>{let n=e.attempts,s=e.sleep;for(;;)try{return await t(...o)}catch(r){if(n--<=0)throw r;await H(Math.floor(Math.random()*s)),s*=2}}}async function H(e){return new Promise(t=>setTimeout(t,e))}var g="aws-cdk:auto-delete-objects",F=JSON.stringify({Version:"2012-10-17",Statement:[]}),c=new h.S3({}),_=R(S);async function S(e){switch(e.RequestType){case"Create":return;case"Update":return U(e);case"Delete":return E(e.ResourceProperties?.BucketName)}}async function U(e){let t=e,o=t.OldResourceProperties?.BucketName,n=t.ResourceProperties?.BucketName;if(n!=null&&o!=null&&n!==o)return E(o)}async function N(e){try{let t=(await c.getBucketPolicy({Bucket:e}))?.Policy??F,o=JSON.parse(t);o.Statement.push({Principal:"*",Effect:"Deny",Action:["s3:PutObject"],Resource:[`arn:aws:s3:::${e}/*`]}),await c.putBucketPolicy({Bucket:e,Policy:JSON.stringify(o)})}catch(t){if(t.name==="NoSuchBucket")throw t;console.log(`Could not set new object deny policy on bucket '${e}' prior to deletion.`)}}async function f(e){let t=await c.listObjectVersions({Bucket:e}),o=[...t.Versions??[],...t.DeleteMarkers??[]];if(o.length===0)return;let n=o.map(s=>({Key:s.Key,VersionId:s.VersionId}));await c.deleteObjects({Bucket:e,Delete:{Objects:n}}),t?.IsTruncated&&await f(e)}async function E(e){if(!e)throw new Error("No BucketName was provided.");try{if(!await W(e)){console.log(`Bucket does not have '${g}' tag, skipping cleaning.`);return}await N(e),await f(e)}catch(t){if(t.name==="NoSuchBucket"){console.log(`Bucket '${e}' does not exist.`);return}throw t}}async function W(e){return(await c.getBucketTagging({Bucket:e})).TagSet?.some(o=>o.Key===g&&o.Value==="true")} diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/cdk.out b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/cdk.out new file mode 100644 index 000000000..1f0068d32 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaults.assets.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaults.assets.json new file mode 100644 index 000000000..dd4d5398e --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaults.assets.json @@ -0,0 +1,32 @@ +{ + "version": "36.0.0", + "files": { + "6c1e9b465fa4b2d651dbc9ce3e732d8702a7b19137327684a71d89f1d355f1a2": { + "source": { + "path": "asset.6c1e9b465fa4b2d651dbc9ce3e732d8702a7b19137327684a71d89f1d355f1a2", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6c1e9b465fa4b2d651dbc9ce3e732d8702a7b19137327684a71d89f1d355f1a2.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "2161142d5baee33bf29b5438c80e578a67773313c3407242b4229224aa35b9aa": { + "source": { + "path": "defaults.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "2161142d5baee33bf29b5438c80e578a67773313c3407242b4229224aa35b9aa.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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaults.template.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaults.template.json new file mode 100644 index 000000000..9b49f3421 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaults.template.json @@ -0,0 +1,386 @@ +{ + "Resources": { + "integtesttestS3LoggingBucket91D581BF": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ], + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W35", + "reason": "This S3 bucket is used as the access logging bucket for another bucket" + } + ] + } + } + }, + "integtesttestS3LoggingBucketPolicy8C3AC577": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "integtesttestS3LoggingBucket91D581BF" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "s3:PutObject", + "Condition": { + "ArnLike": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + } + }, + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "logging.s3.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + "/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "integtesttestS3LoggingBucketAutoDeleteObjectsCustomResourceA4C82217": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "integtesttestS3LoggingBucket91D581BF" + } + }, + "DependsOn": [ + "integtesttestS3LoggingBucketPolicy8C3AC577" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integtesttestS3Bucket42B91B48": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "LifecycleConfiguration": { + "Rules": [ + { + "NoncurrentVersionTransitions": [ + { + "StorageClass": "GLACIER", + "TransitionInDays": 90 + } + ], + "Status": "Enabled" + } + ] + }, + "LoggingConfiguration": { + "DestinationBucketName": { + "Ref": "integtesttestS3LoggingBucket91D581BF" + } + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integtesttestS3BucketPolicy54E2DE38": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "integtesttestS3Bucket42B91B48" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "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": "6c1e9b465fa4b2d651dbc9ce3e732d8702a7b19137327684a71d89f1d355f1a2.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "integtesttestS3LoggingBucket91D581BF" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "CDK generated custom resource" + }, + { + "id": "W89", + "reason": "CDK generated custom resource" + }, + { + "id": "W92", + "reason": "CDK generated custom resource" + } + ] + } + } + } + }, + "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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaultsIntegDefaultTestDeployAssert1EF12E47.assets.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaultsIntegDefaultTestDeployAssert1EF12E47.assets.json new file mode 100644 index 000000000..587d9579c --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaultsIntegDefaultTestDeployAssert1EF12E47.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "defaultsIntegDefaultTestDeployAssert1EF12E47.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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaultsIntegDefaultTestDeployAssert1EF12E47.template.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaultsIntegDefaultTestDeployAssert1EF12E47.template.json new file mode 100644 index 000000000..ad9d0fb73 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/defaultsIntegDefaultTestDeployAssert1EF12E47.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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/integ.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/integ.json new file mode 100644 index 000000000..09c22828e --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "36.0.0", + "testCases": { + "defaults/Integ/DefaultTest": { + "stacks": [ + "defaults" + ], + "assertionStack": "defaults/Integ/DefaultTest/DeployAssert", + "assertionStackName": "defaultsIntegDefaultTestDeployAssert1EF12E47" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/manifest.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/manifest.json new file mode 100644 index 000000000..1bdf5b75d --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/manifest.json @@ -0,0 +1,149 @@ +{ + "version": "36.0.0", + "artifacts": { + "defaultsIntegDefaultTestDeployAssert1EF12E47.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "defaultsIntegDefaultTestDeployAssert1EF12E47.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "defaultsIntegDefaultTestDeployAssert1EF12E47": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "defaultsIntegDefaultTestDeployAssert1EF12E47.template.json", + "terminationProtection": false, + "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": [ + "defaultsIntegDefaultTestDeployAssert1EF12E47.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": [ + "defaultsIntegDefaultTestDeployAssert1EF12E47.assets" + ], + "metadata": { + "/defaults/Integ/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/defaults/Integ/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "defaults/Integ/DefaultTest/DeployAssert" + }, + "defaults.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "defaults.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "defaults": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "defaults.template.json", + "terminationProtection": false, + "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}/2161142d5baee33bf29b5438c80e578a67773313c3407242b4229224aa35b9aa.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "defaults.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": [ + "defaults.assets" + ], + "metadata": { + "/defaults/integ-test/testS3LoggingBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integtesttestS3LoggingBucket91D581BF" + } + ], + "/defaults/integ-test/testS3LoggingBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integtesttestS3LoggingBucketPolicy8C3AC577" + } + ], + "/defaults/integ-test/testS3LoggingBucket/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "integtesttestS3LoggingBucketAutoDeleteObjectsCustomResourceA4C82217" + } + ], + "/defaults/integ-test/testS3Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integtesttestS3Bucket42B91B48" + } + ], + "/defaults/integ-test/testS3Bucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integtesttestS3BucketPolicy54E2DE38" + } + ], + "/defaults/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/defaults/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/defaults/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/defaults/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "defaults" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/tree.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/tree.json new file mode 100644 index 000000000..3bf2294dd --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.js.snapshot/tree.json @@ -0,0 +1,474 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "defaults": { + "id": "defaults", + "path": "defaults", + "children": { + "integ-test": { + "id": "integ-test", + "path": "defaults/integ-test", + "children": { + "testS3LoggingBucket": { + "id": "testS3LoggingBucket", + "path": "defaults/integ-test/testS3LoggingBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "defaults/integ-test/testS3LoggingBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "AES256" + } + } + ] + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + }, + "tags": [ + { + "key": "aws-cdk:auto-delete-objects", + "value": "true" + } + ], + "versioningConfiguration": { + "status": "Enabled" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", + "version": "2.135.0" + } + }, + "Policy": { + "id": "Policy", + "path": "defaults/integ-test/testS3LoggingBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "defaults/integ-test/testS3LoggingBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "integtesttestS3LoggingBucket91D581BF" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "s3:PutObject", + "Condition": { + "ArnLike": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + } + }, + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "logging.s3.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3LoggingBucket91D581BF", + "Arn" + ] + }, + "/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", + "version": "2.135.0" + } + }, + "AutoDeleteObjectsCustomResource": { + "id": "AutoDeleteObjectsCustomResource", + "path": "defaults/integ-test/testS3LoggingBucket/AutoDeleteObjectsCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "defaults/integ-test/testS3LoggingBucket/AutoDeleteObjectsCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.Bucket", + "version": "2.135.0" + } + }, + "testS3Bucket": { + "id": "testS3Bucket", + "path": "defaults/integ-test/testS3Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "defaults/integ-test/testS3Bucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "AES256" + } + } + ] + }, + "lifecycleConfiguration": { + "rules": [ + { + "noncurrentVersionTransitions": [ + { + "storageClass": "GLACIER", + "transitionInDays": 90 + } + ], + "status": "Enabled" + } + ] + }, + "loggingConfiguration": { + "destinationBucketName": { + "Ref": "integtesttestS3LoggingBucket91D581BF" + } + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + }, + "versioningConfiguration": { + "status": "Enabled" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", + "version": "2.135.0" + } + }, + "Policy": { + "id": "Policy", + "path": "defaults/integ-test/testS3Bucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "defaults/integ-test/testS3Bucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "integtesttestS3Bucket42B91B48" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.Bucket", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-solutions-constructs/aws-constructs-factories.ConstructsFactories", + "version": "2.55.0" + } + }, + "Custom::S3AutoDeleteObjectsCustomResourceProvider": { + "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", + "path": "defaults/Custom::S3AutoDeleteObjectsCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "defaults/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "2.135.0" + } + }, + "Role": { + "id": "Role", + "path": "defaults/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.135.0" + } + }, + "Handler": { + "id": "Handler", + "path": "defaults/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "2.135.0" + } + }, + "Integ": { + "id": "Integ", + "path": "defaults/Integ", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "defaults/Integ/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "defaults/Integ/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "defaults/Integ/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "defaults/Integ/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.135.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "defaults/Integ/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "2.135.0-alpha.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "2.135.0-alpha.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "defaults/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.135.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "defaults/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.135.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "2.135.0" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.ts b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.ts new file mode 100644 index 000000000..4bb6def9c --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.defaults.ts @@ -0,0 +1,39 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +/// !cdk-integ * +import { App, Stack, RemovalPolicy } from "aws-cdk-lib"; +import { ConstructsFactories } from "../../lib"; +import { generateIntegStackName, suppressCustomHandlerCfnNagWarnings } from '@aws-solutions-constructs/core'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); + +// Empty arguments +const stack = new Stack(app, generateIntegStackName(__filename)); + +const factories = new ConstructsFactories(stack, 'integ-test'); + +factories.s3BucketFactory('test', { + bucketProps: { removalPolicy: RemovalPolicy.DESTROY }, + loggingBucketProps: { + removalPolicy: RemovalPolicy.DESTROY, + autoDeleteObjects: true + } +}); + +suppressCustomHandlerCfnNagWarnings(stack, 'Custom::S3AutoDeleteObjectsCustomResourceProvider'); + +new IntegTest(stack, 'Integ', { testCases: [ + stack +] }); diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/cdk.out b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/cdk.out new file mode 100644 index 000000000..1f0068d32 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/integ.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/integ.json new file mode 100644 index 000000000..5654a4af4 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "36.0.0", + "testCases": { + "no-logging/Integ/DefaultTest": { + "stacks": [ + "no-logging" + ], + "assertionStack": "no-logging/Integ/DefaultTest/DeployAssert", + "assertionStackName": "nologgingIntegDefaultTestDeployAssert09C268F5" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/manifest.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/manifest.json new file mode 100644 index 000000000..08b2850c1 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/manifest.json @@ -0,0 +1,119 @@ +{ + "version": "36.0.0", + "artifacts": { + "nologgingIntegDefaultTestDeployAssert09C268F5.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "nologgingIntegDefaultTestDeployAssert09C268F5.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "nologgingIntegDefaultTestDeployAssert09C268F5": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "nologgingIntegDefaultTestDeployAssert09C268F5.template.json", + "terminationProtection": false, + "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": [ + "nologgingIntegDefaultTestDeployAssert09C268F5.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": [ + "nologgingIntegDefaultTestDeployAssert09C268F5.assets" + ], + "metadata": { + "/no-logging/Integ/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/no-logging/Integ/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "no-logging/Integ/DefaultTest/DeployAssert" + }, + "no-logging.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "no-logging.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "no-logging": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "no-logging.template.json", + "terminationProtection": false, + "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}/23dbcd10d45309f94f648003a2115c8b94f390195e05964a3633c389b31a54f5.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "no-logging.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": [ + "no-logging.assets" + ], + "metadata": { + "/no-logging/integ-test/testS3Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integtesttestS3Bucket42B91B48" + } + ], + "/no-logging/integ-test/testS3Bucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integtesttestS3BucketPolicy54E2DE38" + } + ], + "/no-logging/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/no-logging/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "no-logging" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/no-logging.assets.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/no-logging.assets.json new file mode 100644 index 000000000..0c87f0603 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/no-logging.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "23dbcd10d45309f94f648003a2115c8b94f390195e05964a3633c389b31a54f5": { + "source": { + "path": "no-logging.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "23dbcd10d45309f94f648003a2115c8b94f390195e05964a3633c389b31a54f5.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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/no-logging.template.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/no-logging.template.json new file mode 100644 index 000000000..624268794 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/no-logging.template.json @@ -0,0 +1,133 @@ +{ + "Resources": { + "integtesttestS3Bucket42B91B48": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "LifecycleConfiguration": { + "Rules": [ + { + "NoncurrentVersionTransitions": [ + { + "StorageClass": "GLACIER", + "TransitionInDays": 90 + } + ], + "Status": "Enabled" + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W35", + "reason": "Access Logging disabled intentionally on this bucket for the test." + } + ] + } + } + }, + "integtesttestS3BucketPolicy54E2DE38": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "integtesttestS3Bucket42B91B48" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + } + }, + "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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/nologgingIntegDefaultTestDeployAssert09C268F5.assets.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/nologgingIntegDefaultTestDeployAssert09C268F5.assets.json new file mode 100644 index 000000000..d7e99869a --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/nologgingIntegDefaultTestDeployAssert09C268F5.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "nologgingIntegDefaultTestDeployAssert09C268F5.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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/nologgingIntegDefaultTestDeployAssert09C268F5.template.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/nologgingIntegDefaultTestDeployAssert09C268F5.template.json new file mode 100644 index 000000000..ad9d0fb73 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/nologgingIntegDefaultTestDeployAssert09C268F5.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/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/tree.json b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/tree.json new file mode 100644 index 000000000..d75b8c8b8 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.js.snapshot/tree.json @@ -0,0 +1,230 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "no-logging": { + "id": "no-logging", + "path": "no-logging", + "children": { + "integ-test": { + "id": "integ-test", + "path": "no-logging/integ-test", + "children": { + "testS3Bucket": { + "id": "testS3Bucket", + "path": "no-logging/integ-test/testS3Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "no-logging/integ-test/testS3Bucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "AES256" + } + } + ] + }, + "lifecycleConfiguration": { + "rules": [ + { + "noncurrentVersionTransitions": [ + { + "storageClass": "GLACIER", + "transitionInDays": 90 + } + ], + "status": "Enabled" + } + ] + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + }, + "versioningConfiguration": { + "status": "Enabled" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", + "version": "2.135.0" + } + }, + "Policy": { + "id": "Policy", + "path": "no-logging/integ-test/testS3Bucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "no-logging/integ-test/testS3Bucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "integtesttestS3Bucket42B91B48" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "integtesttestS3Bucket42B91B48", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.Bucket", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-solutions-constructs/aws-constructs-factories.ConstructsFactories", + "version": "2.55.0" + } + }, + "Integ": { + "id": "Integ", + "path": "no-logging/Integ", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "no-logging/Integ/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "no-logging/Integ/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "no-logging/Integ/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "no-logging/Integ/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.135.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "no-logging/Integ/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "2.135.0-alpha.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "2.135.0-alpha.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "no-logging/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.135.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "no-logging/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.135.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.135.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "2.135.0" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.ts b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.ts new file mode 100644 index 000000000..0d71fb367 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/integ.no-logging.ts @@ -0,0 +1,43 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +/// !cdk-integ * +import { App, Stack, RemovalPolicy } from "aws-cdk-lib"; +import { ConstructsFactories } from "../../lib"; +import { generateIntegStackName, addCfnSuppressRules, suppressCustomHandlerCfnNagWarnings } from '@aws-solutions-constructs/core'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); + +// Empty arguments +const stack = new Stack(app, generateIntegStackName(__filename)); + +const factories = new ConstructsFactories(stack, 'integ-test'); + +const response = factories.s3BucketFactory('test', { + bucketProps: { removalPolicy: RemovalPolicy.DESTROY }, + logS3AccessLogs: false, +}); + +addCfnSuppressRules(response.s3Bucket, [ + { + id: 'W35', + reason: "Access Logging disabled intentionally on this bucket for the test." + } +]); + +suppressCustomHandlerCfnNagWarnings(stack, 'Custom::S3AutoDeleteObjectsCustomResourceProvider'); + +new IntegTest(stack, 'Integ', { testCases: [ + stack +] }); diff --git a/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/s3-factory.test.ts b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/s3-factory.test.ts new file mode 100644 index 000000000..7b9251a50 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-constructs-factories/test/s3/s3-factory.test.ts @@ -0,0 +1,120 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +import { Stack } from 'aws-cdk-lib'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { Template } from 'aws-cdk-lib/assertions'; +import { ConstructsFactories, /* S3BucketFactoryProps, S3BucketFactoryResponse */ } from "../../lib"; + +test('All defaults', () => { + const stack = new Stack(); + + const factories = new ConstructsFactories(stack, 'target'); + + const newBucketStructure = factories.s3BucketFactory('testBucket', {}); + + expect(newBucketStructure.s3Bucket).toBeDefined(); + expect(newBucketStructure.s3LoggingBucket).toBeDefined(); + + const template = Template.fromStack(stack); + template.resourceCountIs("AWS::S3::Bucket", 2); + template.hasResourceProperties("AWS::S3::Bucket", { + LoggingConfiguration: { + DestinationBucketName: { + Ref: "targettestBucketS3LoggingBucket5E4EA39A" + } + }, + }); +}); + +test('With Logging off', () => { + const stack = new Stack(); + + const factories = new ConstructsFactories(stack, 'target'); + + const newBucketStructure = factories.s3BucketFactory('testBucket', { + logS3AccessLogs: false + }); + + expect(newBucketStructure.s3Bucket).toBeDefined(); + expect(newBucketStructure.s3LoggingBucket).not.toBeDefined(); + + const template = Template.fromStack(stack); + template.resourceCountIs("AWS::S3::Bucket", 1); +}); + +test('Use log bucket props', () => { + const testName = 'my-log-bucket'; + const stack = new Stack(); + + const factories = new ConstructsFactories(stack, 'target'); + + factories.s3BucketFactory('testBucket', { + logS3AccessLogs: true, + loggingBucketProps: { + bucketName: testName + } + }); + + const template = Template.fromStack(stack); + // Did it use the name in the props? + template.hasResourceProperties("AWS::S3::Bucket", { + BucketName: testName + }); +}); + +test('Use existing log bucket props', () => { + const testName = 'my-log-bucket'; + const stack = new Stack(); + + const existingLogBucket = new s3.Bucket(stack, 'existing-log-bucket', { + bucketName: testName + }); + + const factories = new ConstructsFactories(stack, 'target'); + + factories.s3BucketFactory('testBucket', { + bucketProps: { + serverAccessLogsBucket: existingLogBucket + } + }); + + const template = Template.fromStack(stack); + // Does it have the expected number of buckets? + template.resourceCountIs("AWS::S3::Bucket", 2); + template.hasResourceProperties("AWS::S3::Bucket", { + LoggingConfiguration: { + DestinationBucketName: { + Ref: "existinglogbucket385335A9" + } + }, + }); +}); + +test('Catch Props Errors', () => { + const testName = 'my-log-bucket'; + const stack = new Stack(); + + const factories = new ConstructsFactories(stack, 'target'); + + const app = () => { + factories.s3BucketFactory('testBucket', { + logS3AccessLogs: false, + loggingBucketProps: { + bucketName: testName + } + }); + }; + // Assertion + expect(app).toThrowError('Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n'); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/README.md b/source/patterns/@aws-solutions-constructs/core/README.md index 397315537..0f2cdc02b 100644 --- a/source/patterns/@aws-solutions-constructs/core/README.md +++ b/source/patterns/@aws-solutions-constructs/core/README.md @@ -18,6 +18,8 @@ The core library includes the basic building blocks of the AWS Solutions Constructs Library. It defines the core classes that are used in the rest of the AWS Solutions Constructs Library. +> NOTE: Functions in the core library are not part of the published interface for Solutions Constructs. While they are not hidden, using them directly can result in breaking changes outside the scope of a Major release. As many users have expressed an interest in accessing this functionality, we are in the process of exposing this functionality through factories that will produce individual well architected resources. Find the current state of this effort under `aws-constructs-factories`. + ## Default Properties for AWS CDK Constructs Core library sets the default properties for the AWS CDK Constructs used by the AWS Solutions Constructs Library constructs. diff --git a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts index 146daa71f..651c7e60a 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts @@ -173,6 +173,7 @@ export interface BuildS3BucketResponse { /** * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. + * @internal This functionality is exposed externally through aws-constructs-factories */ export function buildS3Bucket(scope: Construct, props: BuildS3BucketProps,